]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/oop/oop.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / oop / oop.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
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 /**
19  * The following methods are added to the YUI instance
20  * @class YUI~oop
21  */
22
23     var L = Y.Lang,
24         A = Y.Array,
25         OP = Object.prototype,
26         CLONE_MARKER = '_~yuim~_',
27         EACH = 'each',
28         SOME = 'some',
29
30         dispatch = function(o, f, c, proto, action) {
31             if (o && o[action] && o !== Y) {
32                 return o[action].call(o, f, c);
33             } else {
34                 switch (A.test(o)) {
35                     case 1:
36                         return A[action](o, f, c);
37                     case 2:
38                         return A[action](Y.Array(o, 0, true), f, c);
39                     default:
40                         return Y.Object[action](o, f, c, proto);
41                 }
42             }
43         };
44
45
46     /**
47      * Applies prototype properties from the supplier to the receiver.
48      * The receiver can be a constructor or an instance.
49      * @method augment
50      * @param {function} r  the object to receive the augmentation.
51      * @param {function} s  the object that supplies the properties to augment.
52      * @param {boolean} ov if true, properties already on the receiver
53      * will be overwritten if found on the supplier.
54      * @param {string[]} wl  a whitelist.  If supplied, only properties in
55      * this list will be applied to the receiver.
56      * @param {Array | Any} args arg or arguments to apply to the supplier
57      * constructor when initializing.
58      * @return {object} the augmented object.
59      *
60      * @todo constructor optional?
61      * @todo understanding what an instance is augmented with
62      * @todo best practices for overriding sequestered methods.
63      */
64     Y.augment = function(r, s, ov, wl, args) {
65         var sProto = s.prototype,
66             newProto = null,
67             construct = s,
68             a = (args) ? Y.Array(args) : [],
69             rProto = r.prototype,
70             target = rProto || r,
71             applyConstructor = false,
72             sequestered, replacements;
73
74         // working on a class, so apply constructor infrastructure
75         if (rProto && construct) {
76             sequestered = {};
77             replacements = {};
78             newProto = {};
79
80             // sequester all of the functions in the supplier and replace with
81             // one that will restore all of them.
82             Y.Object.each(sProto, function(v, k) {
83                 replacements[k] = function() {
84
85             // overwrite the prototype with all of the sequestered functions,
86             // but only if it hasn't been overridden
87                         for (var i in sequestered) {
88                         if (sequestered.hasOwnProperty(i) &&
89                                 (this[i] === replacements[i])) {
90                             this[i] = sequestered[i];
91                         }
92                     }
93
94                     // apply the constructor
95                     construct.apply(this, a);
96
97                     // apply the original sequestered function
98                     return sequestered[k].apply(this, arguments);
99                 };
100
101                 if ((!wl || (k in wl)) && (ov || !(k in this))) {
102                     if (L.isFunction(v)) {
103                         // sequester the function
104                         sequestered[k] = v;
105
106 // replace the sequestered function with a function that will
107 // restore all sequestered functions and exectue the constructor.
108                         this[k] = replacements[k];
109                     } else {
110                         this[k] = v;
111                     }
112                 }
113
114             }, newProto, true);
115
116         // augmenting an instance, so apply the constructor immediately
117         } else {
118             applyConstructor = true;
119         }
120
121         Y.mix(target, newProto || sProto, ov, wl);
122
123         if (applyConstructor) {
124             s.apply(target, a);
125         }
126
127         return r;
128     };
129
130     /**
131      * Applies object properties from the supplier to the receiver.  If
132      * the target has the property, and the property is an object, the target
133      * object will be augmented with the supplier's value.  If the property
134      * is an array, the suppliers value will be appended to the target.
135      * @method aggregate
136      * @param {function} r  the object to receive the augmentation.
137      * @param {function} s  the object that supplies the properties to augment.
138      * @param {boolean} ov if true, properties already on the receiver
139      * will be overwritten if found on the supplier.
140      * @param {string[]} wl a whitelist.  If supplied, only properties in
141      * this list will be applied to the receiver.
142      * @return {object} the extended object.
143      */
144     Y.aggregate = function(r, s, ov, wl) {
145         return Y.mix(r, s, ov, wl, 0, true);
146     };
147
148     /**
149      * Utility to set up the prototype, constructor and superclass properties to
150      * support an inheritance strategy that can chain constructors and methods.
151      * Static members will not be inherited.
152      *
153      * @method extend
154      * @param {function} r   the object to modify.
155      * @param {function} s the object to inherit.
156      * @param {object} px prototype properties to add/override.
157      * @param {object} sx static properties to add/override.
158      * @return {object} the extended object.
159      */
160     Y.extend = function(r, s, px, sx) {
161         if (!s || !r) {
162             Y.error('extend failed, verify dependencies');
163         }
164
165         var sp = s.prototype, rp = Y.Object(sp);
166         r.prototype = rp;
167
168         rp.constructor = r;
169         r.superclass = sp;
170
171         // assign constructor property
172         if (s != Object && sp.constructor == OP.constructor) {
173             sp.constructor = s;
174         }
175
176         // add prototype overrides
177         if (px) {
178             Y.mix(rp, px, true);
179         }
180
181         // add object overrides
182         if (sx) {
183             Y.mix(r, sx, true);
184         }
185
186         return r;
187     };
188
189     /**
190      * Executes the supplied function for each item in
191      * a collection.  Supports arrays, objects, and
192      * Y.NodeLists
193      * @method each
194      * @param {object} o the object to iterate.
195      * @param {function} f the function to execute.  This function
196      * receives the value, key, and object as parameters.
197      * @param {object} c the execution context for the function.
198      * @param {boolean} proto if true, prototype properties are
199      * iterated on objects.
200      * @return {YUI} the YUI instance.
201      */
202     Y.each = function(o, f, c, proto) {
203         return dispatch(o, f, c, proto, EACH);
204     };
205
206     /**
207      * Executes the supplied function for each item in
208      * a collection.  The operation stops if the function
209      * returns true. Supports arrays, objects, and
210      * Y.NodeLists.
211      * @method some
212      * @param {object} o the object to iterate.
213      * @param {function} f the function to execute.  This function
214      * receives the value, key, and object as parameters.
215      * @param {object} c the execution context for the function.
216      * @param {boolean} proto if true, prototype properties are
217      * iterated on objects.
218      * @return {boolean} true if the function ever returns true,
219      * false otherwise.
220      */
221     Y.some = function(o, f, c, proto) {
222         return dispatch(o, f, c, proto, SOME);
223     };
224
225     /**
226      * Deep obj/array copy.  Function clones are actually
227      * wrappers around the original function.
228      * Array-like objects are treated as arrays.
229      * Primitives are returned untouched.  Optionally, a
230      * function can be provided to handle other data types,
231      * filter keys, validate values, etc.
232      *
233      * @method clone
234      * @param {object} o what to clone.
235      * @param {boolean} safe if true, objects will not have prototype
236      * items from the source.  If false, they will.  In this case, the
237      * original is initially protected, but the clone is not completely
238      * immune from changes to the source object prototype.  Also, cloned
239      * prototype items that are deleted from the clone will result
240      * in the value of the source prototype being exposed.  If operating
241      * on a non-safe clone, items should be nulled out rather than deleted.
242      * @param {function} f optional function to apply to each item in a
243      * collection; it will be executed prior to applying the value to
244      * the new object.  Return false to prevent the copy.
245      * @param {object} c optional execution context for f.
246      * @param {object} owner Owner object passed when clone is iterating
247      * an object.  Used to set up context for cloned functions.
248      * @param {object} cloned hash of previously cloned objects to avoid
249      * multiple clones.
250      * @return {Array|Object} the cloned object.
251      */
252     Y.clone = function(o, safe, f, c, owner, cloned) {
253
254         if (!L.isObject(o)) {
255             return o;
256         }
257
258         // @todo cloning YUI instances doesn't currently work
259         if (Y.instanceOf(o, YUI)) {
260             return o;
261         }
262
263         var o2, marked = cloned || {}, stamp,
264             yeach = Y.each;
265
266         switch (L.type(o)) {
267             case 'date':
268                 return new Date(o);
269             case 'regexp':
270                 // if we do this we need to set the flags too
271                 // return new RegExp(o.source);
272                 return o;
273             case 'function':
274                 // o2 = Y.bind(o, owner);
275                 // break;
276                 return o;
277             case 'array':
278                 o2 = [];
279                 break;
280             default:
281
282                 // #2528250 only one clone of a given object should be created.
283                 if (o[CLONE_MARKER]) {
284                     return marked[o[CLONE_MARKER]];
285                 }
286
287                 stamp = Y.guid();
288
289                 o2 = (safe) ? {} : Y.Object(o);
290
291                 o[CLONE_MARKER] = stamp;
292                 marked[stamp] = o;
293         }
294
295         // #2528250 don't try to clone element properties
296         if (!o.addEventListener && !o.attachEvent) {
297             yeach(o, function(v, k) {
298 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
299                     if (k !== CLONE_MARKER) {
300                         if (k == 'prototype') {
301                             // skip the prototype
302                         // } else if (o[k] === o) {
303                         //     this[k] = this;
304                         } else {
305                             this[k] =
306                                 Y.clone(v, safe, f, c, owner || o, marked);
307                         }
308                     }
309                 }
310             }, o2);
311         }
312
313         if (!cloned) {
314             Y.Object.each(marked, function(v, k) {
315                 if (v[CLONE_MARKER]) {
316                     try {
317                         delete v[CLONE_MARKER];
318                     } catch (e) {
319                         v[CLONE_MARKER] = null;
320                     }
321                 }
322             }, this);
323             marked = null;
324         }
325
326         return o2;
327     };
328
329
330     /**
331      * Returns a function that will execute the supplied function in the
332      * supplied object's context, optionally adding any additional
333      * supplied parameters to the beginning of the arguments collection the
334      * supplied to the function.
335      *
336      * @method bind
337      * @param {Function|String} f the function to bind, or a function name
338      * to execute on the context object.
339      * @param {object} c the execution context.
340      * @param {any} args* 0..n arguments to include before the arguments the
341      * function is executed with.
342      * @return {function} the wrapped function.
343      */
344     Y.bind = function(f, c) {
345         var xargs = arguments.length > 2 ?
346                 Y.Array(arguments, 2, true) : null;
347         return function() {
348             var fn = L.isString(f) ? c[f] : f,
349                 args = (xargs) ?
350                     xargs.concat(Y.Array(arguments, 0, true)) : arguments;
351             return fn.apply(c || fn, args);
352         };
353     };
354
355     /**
356      * Returns a function that will execute the supplied function in the
357      * supplied object's context, optionally adding any additional
358      * supplied parameters to the end of the arguments the function
359      * is executed with.
360      *
361      * @method rbind
362      * @param {Function|String} f the function to bind, or a function name
363      * to execute on the context object.
364      * @param {object} c the execution context.
365      * @param {any} args* 0..n arguments to append to the end of
366      * arguments collection supplied to the function.
367      * @return {function} the wrapped function.
368      */
369     Y.rbind = function(f, c) {
370         var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
371         return function() {
372             var fn = L.isString(f) ? c[f] : f,
373                 args = (xargs) ?
374                     Y.Array(arguments, 0, true).concat(xargs) : arguments;
375             return fn.apply(c || fn, args);
376         };
377     };
378
379
380
381 }, '3.3.0' );