oop.js revision 5c69c6f367621a346c43fb031885185b7555f950
1N/AYUI.add('oop', function(Y) {
1N/A
1N/A/**
1N/A * Supplies object inheritance and manipulation utilities. This adds
1N/A * additional functionaity to what is provided in yui-base, and the
1N/A * methods are applied directly to the YUI instance. This module
1N/A * is required for most YUI components.
1N/A * @module oop
1N/A */
1N/A
1N/A var L = Y.Lang,
1N/A A = Y.Array,
1N/A OP = Object.prototype;
1N/A
1N/A /**
1N/A * The following methods are added to the YUI instance
1N/A * @class YUI~oop
1N/A */
1N/A
1N/A /**
1N/A * Applies prototype properties from the supplier to the receiver.
1N/A * The receiver can be a constructor or an instance.
1N/A * @method augment
1N/A * @param {Function} r the object to receive the augmentation
1N/A * @param {Function} s the object that supplies the properties to augment
1N/A * @param ov {boolean} if true, properties already on the receiver
1N/A * will be overwritten if found on the supplier.
1N/A * @param wl {string[]} a whitelist. If supplied, only properties in
1N/A * this list will be applied to the receiver.
1N/A * @param args {Array | Any} arg or arguments to apply to the supplier
1N/A * constructor when initializing.
1N/A * @return {object} the augmented object
1N/A *
1N/A * @todo constructor optional?
1N/A * @todo understanding what an instance is augmented with
1N/A * @TODO best practices for overriding sequestered methods.
1N/A */
1N/A Y.augment = function(r, s, ov, wl, args) {
1N/A var sProto = s.prototype,
1N/A newProto = null,
1N/A construct = s,
1N/A a = (args) ? Y.Array(args) : [],
1N/A rProto = r.prototype,
1N/A target = rProto || r,
1N/A applyConstructor = false,
1N/A sequestered, replacements, i;
1N/A
1N/A // working on a class, so apply constructor infrastructure
1N/A if (rProto && construct) {
1N/A sequestered = {};
1N/A replacements = {};
1N/A newProto = {};
1N/A
1N/A // sequester all of the functions in the supplier and replace with
1N/A // one that will restore all of them.
1N/A Y.each(sProto, function(v, k) {
1N/A replacements[k] = function() {
1N/A
1N/A// overwrite the prototype with all of the sequestered functions,
1N/A// but only if it hasn't been overridden
1N/A for (i in sequestered) {
1N/A if (sequestered.hasOwnProperty(i) && (this[i] === replacements[i])) {
1N/A this[i] = sequestered[i];
1N/A }
1N/A }
1N/A
1N/A // apply the constructor
1N/A construct.apply(this, a);
1N/A
1N/A // apply the original sequestered function
1N/A return sequestered[k].apply(this, arguments);
1N/A };
1N/A
1N/A if ((!wl || (k in wl)) && (ov || !(k in this))) {
1N/A if (L.isFunction(v)) {
1N/A // sequester the function
1N/A sequestered[k] = v;
1N/A
1N/A// replace the sequestered function with a function that will
1N/A// restore all sequestered functions and exectue the constructor.
1N/A this[k] = replacements[k];
1N/A } else {
1N/A this[k] = v;
1N/A }
1N/A
1N/A }
1N/A
1N/A }, newProto, true);
1N/A
1N/A // augmenting an instance, so apply the constructor immediately
1N/A } else {
1N/A applyConstructor = true;
1N/A }
1N/A
1N/A Y.mix(target, newProto || sProto, ov, wl);
1N/A
1N/A if (applyConstructor) {
1N/A s.apply(target, a);
1N/A }
1N/A
1N/A return r;
1N/A };
1N/A
1N/A /**
1N/A * Applies object properties from the supplier to the receiver. If
1N/A * the target has the property, and the property is an object, the target
1N/A * object will be augmented with the supplier's value. If the property
1N/A * is an array, the suppliers value will be appended to the target.
1N/A * @method aggregate
1N/A * @param {Function} r the object to receive the augmentation
1N/A * @param {Function} s the object that supplies the properties to augment
1N/A * @param ov {boolean} if true, properties already on the receiver
1N/A * will be overwritten if found on the supplier.
1N/A * @param wl {string[]} a whitelist. If supplied, only properties in
1N/A * this list will be applied to the receiver.
1N/A * @return {object} the extended object
1N/A */
1N/A Y.aggregate = function(r, s, ov, wl) {
1N/A return Y.mix(r, s, ov, wl, 0, true);
1N/A };
1N/A
1N/A /**
1N/A * Utility to set up the prototype, constructor and superclass properties to
1N/A * support an inheritance strategy that can chain constructors and methods.
1N/A * Static members will not be inherited.
1N/A *
1N/A * @method extend
1N/A * @param {Function} r the object to modify
1N/A * @param {Function} s the object to inherit
1N/A * @param {Object} px prototype properties to add/override
1N/A * @param {Object} sx static properties to add/override
1N/A * @return {YUI} the YUI instance
1N/A */
1N/A Y.extend = function(r, s, px, sx) {
1N/A if (!s||!r) {
1N/A // @TODO error symbols
1N/A Y.error("extend failed, verify dependencies");
1N/A }
1N/A
1N/A var sp = s.prototype, rp=Y.Object(sp);
1N/A r.prototype=rp;
1N/A
1N/A rp.constructor=r;
1N/A r.superclass=sp;
1N/A
1N/A // assign constructor property
1N/A if (s != Object && sp.constructor == OP.constructor) {
1N/A sp.constructor=s;
1N/A }
1N/A
1N/A // add prototype overrides
1N/A if (px) {
1N/A Y.mix(rp, px, true);
1N/A }
1N/A
1N/A // add object overrides
1N/A if (sx) {
1N/A Y.mix(r, sx, true);
1N/A }
1N/A
1N/A return r;
1N/A };
1N/A
1N/A /**
1N/A * Executes the supplied function for each item in
1N/A * a collection. Supports arrays, objects, and
1N/A * Y.NodeLists
1N/A * @method each
1N/A * @param o the object to iterate
1N/A * @param f the function to execute. This function
1N/A * receives the value, key, and object as parameters
1N/A * @param proto if true, prototype properties are
1N/A * iterated on objects
1N/A * @return {YUI} the YUI instance
1N/A */
1N/A Y.each = function(o, f, c, proto) {
1N/A
1N/A if (o.each && o.item) {
1N/A return o.each.call(o, f, c);
1N/A } else {
1N/A switch (A.test(o)) {
1N/A case 1:
1N/A return A.each(o, f, c);
1N/A case 2:
1N/A return A.each(Y.Array(o, 0, true), f, c);
1N/A default:
1N/A return Y.Object.each(o, f, c, proto);
1N/A }
1N/A }
1N/A
1N/A // return Y.Object.each(o, f, c);
1N/A };
1N/A
1N/A /**
1N/A * Deep obj/array copy. Functions are cloned with Y.bind.
1N/A * Array-like objects are treated as arrays.
1N/A * Primitives are returned untouched. Optionally, a
1N/A * function can be provided to handle other data types,
1N/A * filter keys, validate values, etc.
1N/A *
1N/A * @method clone
1N/A * @param o what to clone
1N/A * @param safe {boolean} if true, objects will not have prototype
1N/A * items from the source. If false, they will. In this case, the
1N/A * original is initially protected, but the clone is not completely immune
1N/A * from changes to the source object prototype. Also, cloned prototype
1N/A * items that are deleted from the clone will result in the value
1N/A * of the source prototype being exposed. If operating on a non-safe
1N/A * clone, items should be nulled out rather than deleted.
1N/A * @TODO review
1N/A * @param f optional function to apply to each item in a collection;
1N/A * it will be executed prior to applying the value to
1N/A * the new object. Return false to prevent the copy.
1N/A * @param c optional execution context for f
1N/A * @param owner Owner object passed when clone is iterating an
1N/A * object. Used to set up context for cloned functions.
1N/A * @return {Array|Object} the cloned object
1N/A */
1N/A Y.clone = function(o, safe, f, c, owner) {
1N/A
1N/A
1N/A if (!L.isObject(o)) {
1N/A return o;
1N/A }
1N/A
1N/A var Node = Y.Node, o2;
1N/A
1N/A switch (L.type(o)) {
1N/A case 'date':
1N/A return new Date(o);
1N/A case 'regexp':
1N/A return new RegExp(o.source);
1N/A case 'function':
1N/A o2 = Y.bind(o, owner);
1N/A break;
1N/A case 'array':
1N/A o2 = [];
1N/A break;
1N/A default:
1N/A // workaround for #2528250
1N/A if (Node && o instanceof Node) {
1N/A return new Node(o._node);
1N/A }
1N/A o2 = (safe) ? {} : Y.Object(o);
1N/A }
1N/A
1N/A Y.each(o, function(v, k) {
1N/A if (!f || (f.call(c || this, v, k, this, o) !== false)) {
1N/A this[k] = Y.clone(v, safe, f, c, owner || o);
1N/A }
1N/A }, o2);
1N/A
1N/A return o2;
1N/A };
1N/A
1N/A
1N/A /**
1N/A * Returns a function that will execute the supplied function in the
1N/A * supplied object's context, optionally adding any additional
1N/A * supplied parameters to the beginning of the arguments collection the
1N/A * supplied to the function.
1N/A *
1N/A * @method bind
1N/A * @param f {Function|String} the function to bind, or a function name
1N/A * to execute on the context object
1N/A * @param c the execution context
1N/A * @param args* 0..n arguments to include before the arguments the
1N/A * function is executed with.
1N/A * @return {function} the wrapped function
1N/A */
1N/A Y.bind = function(f, c) {
1N/A var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
1N/A return function () {
1N/A var fn = L.isString(f) ? c[f] : f,
1N/A args = (xargs) ? xargs.concat(Y.Array(arguments, 0, true)) : arguments;
1N/A return fn.apply(c || fn, args);
1N/A };
1N/A };
1N/A
1N/A /**
1N/A * Returns a function that will execute the supplied function in the
1N/A * supplied object's context, optionally adding any additional
1N/A * supplied parameters to the end of the arguments the function
1N/A * is executed with.
1N/A *
1N/A * @method rbind
1N/A * @param f {Function|String} the function to bind, or a function name
1N/A * to execute on the context object
1N/A * @param c the execution context
1N/A * @param args* 0..n arguments to append to the end of arguments collection
1N/A * supplied to the function
1N/A * @return {function} the wrapped function
1N/A */
1N/A Y.rbind = function(f, c) {
1N/A var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
1N/A return function () {
1N/A var fn = L.isString(f) ? c[f] : f,
1N/A args = (xargs) ? Y.Array(arguments, 0, true).concat(xargs) : arguments;
1N/A return fn.apply(c || fn, args);
1N/A };
1N/A };
1N/A
1N/A
1N/A
1N/A}, '@VERSION@' );
1N/A