Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('oop', function (Y, NAME) {
2
 
3
/**
4
Adds object inheritance and manipulation utilities to the YUI instance. This
5
module is required by most YUI components.
6
 
7
@module oop
8
**/
9
 
10
var L            = Y.Lang,
11
    A            = Y.Array,
12
    OP           = Object.prototype,
13
    CLONE_MARKER = '_~yuim~_',
14
 
15
    hasOwn   = OP.hasOwnProperty,
16
    toString = OP.toString;
17
 
18
/**
19
Calls the specified _action_ method on _o_ if it exists. Otherwise, if _o_ is an
20
array, calls the _action_ method on `Y.Array`, or if _o_ is an object, calls the
21
_action_ method on `Y.Object`.
22
 
23
If _o_ is an array-like object, it will be coerced to an array.
24
 
25
This is intended to be used with array/object iteration methods that share
26
signatures, such as `each()`, `some()`, etc.
27
 
28
@method dispatch
29
@param {Object} o Array or object to dispatch to.
30
@param {Function} f Iteration callback.
31
    @param {Mixed} f.value Value being iterated.
32
    @param {Mixed} f.key Current object key or array index.
33
    @param {Mixed} f.object Object or array being iterated.
34
@param {Object} c `this` object to bind the iteration callback to.
35
@param {Boolean} proto If `true`, prototype properties of objects will be
36
    iterated.
37
@param {String} action Function name to be dispatched on _o_. For example:
38
    'some', 'each', etc.
39
@private
40
@return {Mixed} Returns the value returned by the chosen iteration action, which
41
    varies.
42
**/
43
function dispatch(o, f, c, proto, action) {
44
    if (o && o[action] && o !== Y) {
45
        return o[action].call(o, f, c);
46
    } else {
47
        switch (A.test(o)) {
48
            case 1:
49
                return A[action](o, f, c);
50
            case 2:
51
                return A[action](Y.Array(o, 0, true), f, c);
52
            default:
53
                return Y.Object[action](o, f, c, proto);
54
        }
55
    }
56
}
57
 
58
/**
59
Augments the _receiver_ with prototype properties from the _supplier_. The
60
receiver may be a constructor function or an object. The supplier must be a
61
constructor function.
62
 
63
If the _receiver_ is an object, then the _supplier_ constructor will be called
64
immediately after _receiver_ is augmented, with _receiver_ as the `this` object.
65
 
66
If the _receiver_ is a constructor function, then all prototype methods of
67
_supplier_ that are copied to _receiver_ will be sequestered, and the
68
_supplier_ constructor will not be called immediately. The first time any
69
sequestered method is called on the _receiver_'s prototype, all sequestered
70
methods will be immediately copied to the _receiver_'s prototype, the
71
_supplier_'s constructor will be executed, and finally the newly unsequestered
72
method that was called will be executed.
73
 
74
This sequestering logic sounds like a bunch of complicated voodoo, but it makes
75
it cheap to perform frequent augmentation by ensuring that suppliers'
76
constructors are only called if a supplied method is actually used. If none of
77
the supplied methods is ever used, then there's no need to take the performance
78
hit of calling the _supplier_'s constructor.
79
 
80
@method augment
81
@param {Function|Object} receiver Object or function to be augmented.
82
@param {Function} supplier Function that supplies the prototype properties with
83
  which to augment the _receiver_.
84
@param {Boolean} [overwrite=false] If `true`, properties already on the receiver
85
  will be overwritten if found on the supplier's prototype.
86
@param {String[]} [whitelist] An array of property names. If specified,
87
  only the whitelisted prototype properties will be applied to the receiver, and
88
  all others will be ignored.
89
@param {Array|any} [args] Argument or array of arguments to pass to the
90
  supplier's constructor when initializing.
91
@return {Function} Augmented object.
92
@for YUI
93
**/
94
Y.augment = function (receiver, supplier, overwrite, whitelist, args) {
95
    var rProto    = receiver.prototype,
96
        sequester = rProto && supplier,
97
        sProto    = supplier.prototype,
98
        to        = rProto || receiver,
99
 
100
        copy,
101
        newPrototype,
102
        replacements,
103
        sequestered,
104
        unsequester;
105
 
106
    args = args ? Y.Array(args) : [];
107
 
108
    if (sequester) {
109
        newPrototype = {};
110
        replacements = {};
111
        sequestered  = {};
112
 
113
        copy = function (value, key) {
114
            if (overwrite || !(key in rProto)) {
115
                if (toString.call(value) === '[object Function]') {
116
                    sequestered[key] = value;
117
 
118
                    newPrototype[key] = replacements[key] = function () {
119
                        return unsequester(this, value, arguments);
120
                    };
121
                } else {
122
                    newPrototype[key] = value;
123
                }
124
            }
125
        };
126
 
127
        unsequester = function (instance, fn, fnArgs) {
128
            // Unsequester all sequestered functions.
129
            for (var key in sequestered) {
130
                if (hasOwn.call(sequestered, key)
131
                        && instance[key] === replacements[key]) {
132
 
133
                    instance[key] = sequestered[key];
134
                }
135
            }
136
 
137
            // Execute the supplier constructor.
138
            supplier.apply(instance, args);
139
 
140
            // Finally, execute the original sequestered function.
141
            return fn.apply(instance, fnArgs);
142
        };
143
 
144
        if (whitelist) {
145
            Y.Array.each(whitelist, function (name) {
146
                if (name in sProto) {
147
                    copy(sProto[name], name);
148
                }
149
            });
150
        } else {
151
            Y.Object.each(sProto, copy, null, true);
152
        }
153
    }
154
 
155
    Y.mix(to, newPrototype || sProto, overwrite, whitelist);
156
 
157
    if (!sequester) {
158
        supplier.apply(to, args);
159
    }
160
 
161
    return receiver;
162
};
163
 
164
/**
165
 * Copies object properties from the supplier to the receiver. If the target has
166
 * the property, and the property is an object, the target object will be
167
 * augmented with the supplier's value.
168
 *
169
 * @method aggregate
170
 * @param {Object} receiver Object to receive the augmentation.
171
 * @param {Object} supplier Object that supplies the properties with which to
172
 *     augment the receiver.
173
 * @param {Boolean} [overwrite=false] If `true`, properties already on the receiver
174
 *     will be overwritten if found on the supplier.
175
 * @param {String[]} [whitelist] Whitelist. If supplied, only properties in this
176
 *     list will be applied to the receiver.
177
 * @return {Object} Augmented object.
178
 */
179
Y.aggregate = function(r, s, ov, wl) {
180
    return Y.mix(r, s, ov, wl, 0, true);
181
};
182
 
183
/**
184
 * Utility to set up the prototype, constructor and superclass properties to
185
 * support an inheritance strategy that can chain constructors and methods.
186
 * Static members will not be inherited.
187
 *
188
 * @method extend
189
 * @param {function} r   the object to modify.
190
 * @param {function} s the object to inherit.
191
 * @param {object} px prototype properties to add/override.
192
 * @param {object} sx static properties to add/override.
193
 * @return {object} the extended object.
194
 */
195
Y.extend = function(r, s, px, sx) {
196
    if (!s || !r) {
197
        Y.error('extend failed, verify dependencies');
198
    }
199
 
200
    var sp = s.prototype, rp = Y.Object(sp);
201
    r.prototype = rp;
202
 
203
    rp.constructor = r;
204
    r.superclass = sp;
205
 
206
    // assign constructor property
207
    if (s != Object && sp.constructor == OP.constructor) {
208
        sp.constructor = s;
209
    }
210
 
211
    // add prototype overrides
212
    if (px) {
213
        Y.mix(rp, px, true);
214
    }
215
 
216
    // add object overrides
217
    if (sx) {
218
        Y.mix(r, sx, true);
219
    }
220
 
221
    return r;
222
};
223
 
224
/**
225
 * Executes the supplied function for each item in
226
 * a collection.  Supports arrays, objects, and
227
 * NodeLists
228
 * @method each
229
 * @param {object} o the object to iterate.
230
 * @param {function} f the function to execute.  This function
231
 * receives the value, key, and object as parameters.
232
 * @param {object} c the execution context for the function.
233
 * @param {boolean} proto if true, prototype properties are
234
 * iterated on objects.
235
 * @return {YUI} the YUI instance.
236
 */
237
Y.each = function(o, f, c, proto) {
238
    return dispatch(o, f, c, proto, 'each');
239
};
240
 
241
/**
242
 * Executes the supplied function for each item in
243
 * a collection.  The operation stops if the function
244
 * returns true. Supports arrays, objects, and
245
 * NodeLists.
246
 * @method some
247
 * @param {object} o the object to iterate.
248
 * @param {function} f the function to execute.  This function
249
 * receives the value, key, and object as parameters.
250
 * @param {object} c the execution context for the function.
251
 * @param {boolean} proto if true, prototype properties are
252
 * iterated on objects.
253
 * @return {boolean} true if the function ever returns true,
254
 * false otherwise.
255
 */
256
Y.some = function(o, f, c, proto) {
257
    return dispatch(o, f, c, proto, 'some');
258
};
259
 
260
/**
261
Deep object/array copy. Function clones are actually wrappers around the
262
original function. Array-like objects are treated as arrays. Primitives are
263
returned untouched. Optionally, a function can be provided to handle other data
264
types, filter keys, validate values, etc.
265
 
266
**Note:** Cloning a non-trivial object is a reasonably heavy operation, due to
267
the need to recursively iterate down non-primitive properties. Clone should be
268
used only when a deep clone down to leaf level properties is explicitly
269
required. This method will also
270
 
271
In many cases (for example, when trying to isolate objects used as hashes for
272
configuration properties), a shallow copy, using `Y.merge()` is normally
273
sufficient. If more than one level of isolation is required, `Y.merge()` can be
274
used selectively at each level which needs to be isolated from the original
275
without going all the way to leaf properties.
276
 
277
@method clone
278
@param {object} o what to clone.
279
@param {boolean} safe if true, objects will not have prototype items from the
280
    source. If false, they will. In this case, the original is initially
281
    protected, but the clone is not completely immune from changes to the source
282
    object prototype. Also, cloned prototype items that are deleted from the
283
    clone will result in the value of the source prototype being exposed. If
284
    operating on a non-safe clone, items should be nulled out rather than
285
    deleted.
286
@param {function} f optional function to apply to each item in a collection; it
287
    will be executed prior to applying the value to the new object.
288
    Return false to prevent the copy.
289
@param {object} c optional execution context for f.
290
@param {object} owner Owner object passed when clone is iterating an object.
291
    Used to set up context for cloned functions.
292
@param {object} cloned hash of previously cloned objects to avoid multiple
293
    clones.
294
@return {Array|Object} the cloned object.
295
**/
296
Y.clone = function(o, safe, f, c, owner, cloned) {
297
    var o2, marked, stamp;
298
 
299
    // Does not attempt to clone:
300
    //
301
    // * Non-typeof-object values, "primitive" values don't need cloning.
302
    //
303
    // * YUI instances, cloning complex object like YUI instances is not
304
    //   advised, this is like cloning the world.
305
    //
306
    // * DOM nodes (#2528250), common host objects like DOM nodes cannot be
307
    //   "subclassed" in Firefox and old versions of IE. Trying to use
308
    //   `Object.create()` or `Y.extend()` on a DOM node will throw an error in
309
    //   these browsers.
310
    //
311
    // Instad, the passed-in `o` will be return as-is when it matches one of the
312
    // above criteria.
313
    if (!L.isObject(o) ||
314
            Y.instanceOf(o, YUI) ||
315
            (o.addEventListener || o.attachEvent)) {
316
 
317
        return o;
318
    }
319
 
320
    marked = cloned || {};
321
 
322
    switch (L.type(o)) {
323
        case 'date':
324
            return new Date(o);
325
        case 'regexp':
326
            // if we do this we need to set the flags too
327
            // return new RegExp(o.source);
328
            return o;
329
        case 'function':
330
            // o2 = Y.bind(o, owner);
331
            // break;
332
            return o;
333
        case 'array':
334
            o2 = [];
335
            break;
336
        default:
337
 
338
            // #2528250 only one clone of a given object should be created.
339
            if (o[CLONE_MARKER]) {
340
                return marked[o[CLONE_MARKER]];
341
            }
342
 
343
            stamp = Y.guid();
344
 
345
            o2 = (safe) ? {} : Y.Object(o);
346
 
347
            o[CLONE_MARKER] = stamp;
348
            marked[stamp] = o;
349
    }
350
 
351
    Y.each(o, function(v, k) {
352
        if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
353
            if (k !== CLONE_MARKER) {
354
                if (k == 'prototype') {
355
                    // skip the prototype
356
                // } else if (o[k] === o) {
357
                //     this[k] = this;
358
                } else {
359
                    this[k] =
360
                        Y.clone(v, safe, f, c, owner || o, marked);
361
                }
362
            }
363
        }
364
    }, o2);
365
 
366
    if (!cloned) {
367
        Y.Object.each(marked, function(v, k) {
368
            if (v[CLONE_MARKER]) {
369
                try {
370
                    delete v[CLONE_MARKER];
371
                } catch (e) {
372
                    v[CLONE_MARKER] = null;
373
                }
374
            }
375
        }, this);
376
        marked = null;
377
    }
378
 
379
    return o2;
380
};
381
 
382
/**
383
 * Returns a function that will execute the supplied function in the
384
 * supplied object's context, optionally adding any additional
385
 * supplied parameters to the beginning of the arguments collection the
386
 * supplied to the function.
387
 *
388
 * @method bind
389
 * @param {Function|String} f the function to bind, or a function name
390
 * to execute on the context object.
391
 * @param {object} c the execution context.
392
 * @param {any} args* 0..n arguments to include before the arguments the
393
 * function is executed with.
394
 * @return {function} the wrapped function.
395
 */
396
Y.bind = function(f, c) {
397
    var xargs = arguments.length > 2 ?
398
            Y.Array(arguments, 2, true) : null;
399
    return function() {
400
        var fn = L.isString(f) ? c[f] : f,
401
            args = (xargs) ?
402
                xargs.concat(Y.Array(arguments, 0, true)) : arguments;
403
        return fn.apply(c || fn, args);
404
    };
405
};
406
 
407
/**
408
 * Returns a function that will execute the supplied function in the
409
 * supplied object's context, optionally adding any additional
410
 * supplied parameters to the end of the arguments the function
411
 * is executed with.
412
 *
413
 * @method rbind
414
 * @param {Function|String} f the function to bind, or a function name
415
 * to execute on the context object.
416
 * @param {object} c the execution context.
417
 * @param {any} args* 0..n arguments to append to the end of
418
 * arguments collection supplied to the function.
419
 * @return {function} the wrapped function.
420
 */
421
Y.rbind = function(f, c) {
422
    var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
423
    return function() {
424
        var fn = L.isString(f) ? c[f] : f,
425
            args = (xargs) ?
426
                Y.Array(arguments, 0, true).concat(xargs) : arguments;
427
        return fn.apply(c || fn, args);
428
    };
429
};
430
 
431
 
432
}, '3.18.1', {"requires": ["yui-base"]});