~landscape/lazr-js/trunk

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/3.0.0/build/oop/oop.js

  • Committer: Sidnei da Silva
  • Date: 2009-10-21 21:43:07 UTC
  • mfrom: (120.2.15 yui-3.0.0)
  • mto: (124.5.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 126.
  • Revision ID: sidnei.da.silva@canonical.com-20091021214307-mpul9404n317puk5
- Merge from yui-3.0.0, resolving conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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' );