]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/oop/oop.js
Release 6.2.0beta4
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / oop / oop.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 3.0.0
6 build: 1549
7 */
8 YUI.add('oop', function(Y) {
9
10 /**
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.
15  * @module oop
16  */
17
18     var L  = Y.Lang, 
19         A  = Y.Array,
20         OP = Object.prototype,
21         CLONE_MARKER = "_~yuim~_";
22
23         // dispatch = function(o, f, c, proto, action) {
24         //     if (o[action] && o.item) {
25         //         return o[action].call(o, f, c);
26         //     } else {
27         //         switch (A.test(o)) {
28         //             case 1:
29         //                 return A[action](o, f, c);
30         //             case 2:
31         //                 return A[action](Y.Array(o, 0, true), f, c);
32         //             default:
33         //                 return Y.Object[action](o, f, c, proto);
34         //         }
35         //     }
36         // };
37
38     /**
39      * The following methods are added to the YUI instance
40      * @class YUI~oop
41      */
42
43     /**
44      * Applies prototype properties from the supplier to the receiver.
45      * The receiver can be a constructor or an instance.
46      * @method augment
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
56      *
57      * @todo constructor optional?
58      * @todo understanding what an instance is augmented with
59      * @TODO best practices for overriding sequestered methods.
60      */
61     Y.augment = function(r, s, ov, wl, args) {
62         var sProto           = s.prototype, 
63             newProto         = null, 
64             construct        = s, 
65             a                = (args) ? Y.Array(args) : [], 
66             rProto           = r.prototype, 
67             target           = rProto || r, 
68             applyConstructor = false,
69             sequestered, replacements, i;
70
71         // working on a class, so apply constructor infrastructure
72         if (rProto && construct) {
73             sequestered  = {};
74             replacements = {};
75             newProto     = {};
76
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() {
81
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];
87                         }
88                     }
89
90                     // apply the constructor
91                     construct.apply(this, a);
92
93                     // apply the original sequestered function
94                     return sequestered[k].apply(this, arguments);
95                 };
96
97                 if ((!wl || (k in wl)) && (ov || !(k in this))) {
98                     if (L.isFunction(v)) {
99                         // sequester the function
100                         sequestered[k] = v;
101
102 // replace the sequestered function with a function that will
103 // restore all sequestered functions and exectue the constructor.
104                         this[k] = replacements[k];
105                     } else {
106                         this[k] = v;
107                     }
108
109                 }
110
111             }, newProto, true);
112
113         // augmenting an instance, so apply the constructor immediately
114         } else {
115             applyConstructor = true;
116         }
117
118         Y.mix(target, newProto || sProto, ov, wl);
119
120         if (applyConstructor) {
121             s.apply(target, a);
122         }
123
124         return r;
125     };
126
127     /**
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.
132      * @method aggregate
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
140      */
141     Y.aggregate = function(r, s, ov, wl) {
142         return Y.mix(r, s, ov, wl, 0, true);
143     };
144
145     /**
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.
149      *
150      * @method extend
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
156      */
157     Y.extend = function(r, s, px, sx) {
158         if (!s||!r) {
159             // @TODO error symbols
160             Y.error("extend failed, verify dependencies");
161         }
162
163         var sp = s.prototype, rp=Y.Object(sp);
164         r.prototype=rp;
165
166         rp.constructor=r;
167         r.superclass=sp;
168
169         // assign constructor property
170         if (s != Object && sp.constructor == OP.constructor) {
171             sp.constructor=s;
172         }
173     
174         // add prototype overrides
175         if (px) {
176             Y.mix(rp, px, true);
177         }
178
179         // add object overrides
180         if (sx) {
181             Y.mix(r, sx, true);
182         }
183
184         return r;
185     };
186
187     /**
188      * Executes the supplied function for each item in
189      * a collection.  Supports arrays, objects, and
190      * Y.NodeLists
191      * @method each
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
198      */
199     Y.each = function(o, f, c, proto) {
200
201         if (o.each && o.item) {
202             return o.each.call(o, f, c);
203         } else {
204             switch (A.test(o)) {
205                 case 1:
206                     return A.each(o, f, c);
207                 case 2:
208                     return A.each(Y.Array(o, 0, true), f, c);
209                 default:
210                     return Y.Object.each(o, f, c, proto);
211             }
212         }
213
214         // return Y.Object.each(o, f, c);
215     };
216
217     // Y.each = function(o, f, c, proto) {
218     //     return dispatch(o, f, c, proto, 'each');
219     // };
220
221     /*
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
225      * Y.NodeLists.
226      * @method some
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
233      */
234     // Y.some = function(o, f, c, proto) {
235     //     return dispatch(o, f, c, proto, 'some');
236     // };
237
238     /**
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.
244      *
245      * @method clone
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.
254      * @TODO review
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
262      */
263     Y.clone = function(o, safe, f, c, owner, cloned) {
264
265         if (!L.isObject(o)) {
266             return o;
267         }
268
269         var o2, marked = cloned || {}, stamp;
270
271         switch (L.type(o)) {
272             case 'date':
273                 return new Date(o);
274             case 'regexp':
275                 return new RegExp(o.source);
276             case 'function':
277                 o2 = Y.bind(o, owner);
278                 break;
279             case 'array':
280                 o2 = [];
281                 break;
282             default:
283
284                 // #2528250 only one clone of a given object should be created.
285                 if (o[CLONE_MARKER]) {
286                     return marked[o[CLONE_MARKER]];
287                 }
288
289                 stamp = Y.guid();
290
291                 o2 = (safe) ? {} : Y.Object(o);
292
293                 o[CLONE_MARKER] = stamp;
294                 marked[stamp] = o;
295         }
296
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);
303                     }
304                 }
305             }, o2);
306         }
307
308         if (!cloned) {
309             Y.each(marked, function(v, k) {
310                 delete v[CLONE_MARKER];
311             });
312             marked = null;
313         }
314
315         return o2;
316     };
317
318
319     /**
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.
324      *
325      * @method bind
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
332      */
333     Y.bind = function(f, c) {
334         var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
335         return function () {
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);
339         };
340     };
341     
342     /**
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
346      * is executed with.
347      *
348      * @method rbind
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
355      */
356     Y.rbind = function(f, c) {
357         var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
358         return function () {
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);
362         };
363     };
364
365
366
367 }, '3.0.0' );