yui-core.js revision 43a93fcb59b215be188100c871d728e602476560
/**
* The YUI module contains the components required for building the YUI
* seed file. This includes the script loading mechanism, a simple queue,
* and the core utilities for the library.
* @module yui
* @submodule yui-base
*/
var CACHED_DELIMITER = '__',
NOT_ENUMERATED = ['toString', 'valueOf'],
/*
* IE will not enumerate native functions in a derived object even if the
* function was overridden. This is a workaround for specific functions
* we care about on the Object prototype.
* @property _iefix
* @for YUI
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @private
*/
_iefix = function(r, s) {
var i, fname, fn;
for (i = 0; i < NOT_ENUMERATED.length; i++) {
fname = NOT_ENUMERATED[i];
fn = s[fname];
if (L.isFunction(fn) && fn != Object.prototype[fname]) {
r[fname] = fn;
}
}
};
/**
* Returns a new object containing all of the properties of
* all the supplied objects. The properties from later objects
* will overwrite those in earlier objects. Passing in a
* single object will create a shallow copy of it. For a deep
* copy, use clone.
* @method merge
* @for YUI
* @param arguments {Object*} the objects to merge.
* @return {object} the new merged object.
*/
Y.merge = function() {
var a = arguments, o = {}, i, l = a.length;
for (i = 0; i < l; i = i + 1) {
Y.mix(o, a[i], true);
}
return o;
};
/**
* Applies the supplier's properties to the receiver. By default
* all prototype and static propertes on the supplier are applied
* to the corresponding spot on the receiver. By default all
* properties are applied, and a property that is already on the
* reciever will not be overwritten. The default behavior can
* be modified by supplying the appropriate parameters.
*
* @todo add constants for the modes
*
* @method mix
* @param {Function} r the object to receive the augmentation.
* @param {Function} s the object that supplies the properties to augment.
* @param ov {boolean} if true, properties already on the receiver
* will be overwritten if found on the supplier.
* @param wl {string[]} a whitelist. If supplied, only properties in
* this list will be applied to the receiver.
* @param {int} mode what should be copies, and to where
* default(0): object to object
* 1: prototype to prototype (old augment)
* 2: prototype to prototype and object props (new augment)
* 3: prototype to object
* 4: object to prototype.
* @param merge {boolean/int} merge objects instead of overwriting/ignoring.
* A value of 2 will skip array merge
* Used by Y.aggregate.
* @return {object} the augmented object.
*/
Y.mix = function(r, s, ov, wl, mode, merge) {
if (!s || !r) {
return r || Y;
}
if (mode) {
switch (mode) {
case 1: // proto to proto
return Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
case 2: // object to object and proto to proto
Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
break; // pass through
case 3: // proto to static
return Y.mix(r, s.prototype, ov, wl, 0, merge);
case 4: // static to proto
return Y.mix(r.prototype, s, ov, wl, 0, merge);
default: // object to object is what happens below
}
}
// Maybe don't even need this wl && wl.length check anymore??
var i, l, p, type;
if (wl && wl.length) {
for (i = 0, l = wl.length; i < l; ++i) {
p = wl[i];
type = Y.Lang.type(r[p]);
if (s.hasOwnProperty(p)) {
if (merge && type == 'object') {
Y.mix(r[p], s[p]);
} else if (ov || !r.hasOwnProperty(p)) {
r[p] = s[p];
}
}
}
} else {
for (i in s) {
// if (s.hasOwnProperty(i) && !(i in FROZEN)) {
if (s.hasOwnProperty(i)) {
// check white list if it was supplied
// if the receiver has this property, it is an object,
// and merge is specified, merge the two objects.
if (merge && Y.Lang.isObject(r[i], true)) {
Y.mix(r[i], s[i], ov, wl, 0, true); // recursive
// otherwise apply the property only if overwrite
// is specified or the receiver doesn't have one.
} else if (ov || !r.hasOwnProperty(i)) {
r[i] = s[i];
}
// if merge is specified and the receiver is an array,
// append the array item
// } else if (arr) {
// r.push(s[i]);
// }
}
}
if (Y.UA.ie) {
_iefix(r, s);
}
}
return r;
};
/**
* Returns a wrapper for a function which caches the
* return value of that function, keyed off of the combined
* argument values.
* @method cached
* @param source {function} the function to memoize.
* @param cache an optional cache seed.
* @param refetch if supplied, this value is tested against the cached
* value. If the values are equal, the wrapped function is executed again.
* @return {Function} the wrapped function.
*/
Y.cached = function(source, cache, refetch) {
cache = cache || {};
return function(arg1) {
var k = (arguments.length > 1) ?
Array.prototype.join.call(arguments, CACHED_DELIMITER) : arg1;
if (!(k in cache) || (refetch && cache[k] == refetch)) {
cache[k] = source.apply(source, arguments);
}
return cache[k];
};
};