/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ YUI.add('base-build', function(Y) { /** * The base-build submodule provides Base.build functionality, which * can be used to create custom classes, by aggregating extensions onto * a main class. * * @module base * @submodule base-build * @for Base */ var Base = Y.Base, L = Y.Lang, build; Base._build = function(name, main, extensions, px, sx, cfg) { var build = Base._build, builtClass = build._ctor(main, cfg), buildCfg = build._cfg(main, cfg), _mixCust = build._mixCust, aggregates = buildCfg.aggregates, custom = buildCfg.custom, dynamic = builtClass._yuibuild.dynamic, i, l, val, extClass; if (dynamic && aggregates) { for (i = 0, l = aggregates.length; i < l; ++i) { val = aggregates[i]; if (main.hasOwnProperty(val)) { builtClass[val] = L.isArray(main[val]) ? [] : {}; } } } // Augment/Aggregate for (i = 0, l = extensions.length; i < l; i++) { extClass = extensions[i]; // Prototype, old non-displacing augment Y.mix(builtClass, extClass, true, null, 1); // Custom Statics _mixCust(builtClass, extClass, aggregates, custom); builtClass._yuibuild.exts.push(extClass); } if (px) { Y.mix(builtClass.prototype, px, true); } if (sx) { Y.mix(builtClass, build._clean(sx, aggregates, custom), true); _mixCust(builtClass, sx, aggregates, custom); } builtClass.prototype.hasImpl = build._impl; if (dynamic) { builtClass.NAME = name; builtClass.prototype.constructor = builtClass; } return builtClass; }; build = Base._build; Y.mix(build, { _mixCust: function(r, s, aggregates, custom) { if (aggregates) { Y.aggregate(r, s, true, aggregates); } if (custom) { for (var j in custom) { if (custom.hasOwnProperty(j)) { custom[j](j, r, s); } } } }, _tmpl: function(main) { function BuiltClass() { BuiltClass.superclass.constructor.apply(this, arguments); } Y.extend(BuiltClass, main); return BuiltClass; }, _impl : function(extClass) { var classes = this._getClasses(), i, l, cls, exts, ll, j; for (i = 0, l = classes.length; i < l; i++) { cls = classes[i]; if (cls._yuibuild) { exts = cls._yuibuild.exts; ll = exts.length; for (j = 0; j < ll; j++) { if (exts[j] === extClass) { return true; } } } } return false; }, _ctor : function(main, cfg) { var dynamic = (cfg && false === cfg.dynamic) ? false : true, builtClass = (dynamic) ? build._tmpl(main) : main, buildCfg = builtClass._yuibuild; if (!buildCfg) { buildCfg = builtClass._yuibuild = {}; } buildCfg.id = buildCfg.id || null; buildCfg.exts = buildCfg.exts || []; buildCfg.dynamic = dynamic; return builtClass; }, _cfg : function(main, cfg) { var aggr = [], cust = {}, buildCfg, cfgAggr = (cfg && cfg.aggregates), cfgCustBuild = (cfg && cfg.custom), c = main; while (c && c.prototype) { buildCfg = c._buildCfg; if (buildCfg) { if (buildCfg.aggregates) { aggr = aggr.concat(buildCfg.aggregates); } if (buildCfg.custom) { Y.mix(cust, buildCfg.custom, true); } } c = c.superclass ? c.superclass.constructor : null; } if (cfgAggr) { aggr = aggr.concat(cfgAggr); } if (cfgCustBuild) { Y.mix(cust, cfg.cfgBuild, true); } return { aggregates: aggr, custom: cust }; }, _clean : function(sx, aggregates, custom) { var prop, i, l, sxclone = Y.merge(sx); for (prop in custom) { if (sxclone.hasOwnProperty(prop)) { delete sxclone[prop]; } } for (i = 0, l = aggregates.length; i < l; i++) { prop = aggregates[i]; if (sxclone.hasOwnProperty(prop)) { delete sxclone[prop]; } } return sxclone; } }); /** *

* Builds a custom constructor function (class) from the * main function, and array of extension functions (classes) * provided. The NAME field for the constructor function is * defined by the first argument passed in. *

*

* The cfg object supports the following properties *

*
*
dynamic <boolean>
*
*

If true (default), a completely new class * is created which extends the main class, and acts as the * host on which the extension classes are augmented.

*

If false, the extensions classes are augmented directly to * the main class, modifying the main class' prototype.

*
*
aggregates <String[]>
*
An array of static property names, which will get aggregated * on to the built class, in addition to the default properties build * will always aggregate as defined by the main class' static _buildCfg * property. *
*
* * @method Base.build * @deprecated Use the more convenient Base.create and Base.mix methods instead * @static * @param {Function} name The name of the new class. Used to defined the NAME property for the new class. * @param {Function} main The main class on which to base the built class * @param {Function[]} extensions The set of extension classes which will be * augmented/aggregated to the built class. * @param {Object} cfg Optional. Build configuration for the class (see description). * @return {Function} A custom class, created from the provided main and extension classes */ Base.build = function(name, main, extensions, cfg) { return build(name, main, extensions, null, null, cfg); }; /** *

Creates a new class (constructor function) which extends the base class passed in as the second argument, * and mixes in the array of extensions provided.

*

Prototype properties or methods can be added to the new class, using the px argument (similar to Y.extend).

*

Static properties or methods can be added to the new class, using the sx argument (similar to Y.extend).

*

* *

* @method Base.create * @static * @param {Function} name The name of the newly created class. Used to defined the NAME property for the new class. * @param {Function} main The base class which the new class should extend. This class needs to be Base or a class derived from base (e.g. Widget). * @param {Function[]} extensions The list of extensions which will be mixed into the built class. * @param {Object} px The set of prototype properties/methods to add to the built class. * @param {Object} sx The set of static properties/methods to add to the built class. * @return {Function} The newly created class. */ Base.create = function(name, base, extensions, px, sx) { return build(name, base, extensions, px, sx); }; /** *

Mixes in a list of extensions to an existing class.

* @method Base.mix * @static * @param {Function} main The existing class into which the extensions should be mixed. The class needs to be Base or class derived from base (e.g. Widget) * @param {Function[]} extensions The set of extension classes which will mixed into the existing main class. * @return {Function} The modified main class, with extensions mixed in. */ Base.mix = function(main, extensions) { return build(null, main, extensions, null, null, {dynamic:false}); }; /** * The build configuration for the Base class. * * Defines the static fields which need to be aggregated * when the Base class is used as the main class passed to * the Base.build method. * * @property Base._buildCfg * @type Object * @static * @final * @private */ Base._buildCfg = { custom : { ATTRS : function(prop, r, s) { r.ATTRS = r.ATTRS || {}; if (s.ATTRS) { var sAttrs = s.ATTRS, rAttrs = r.ATTRS, a; for (a in sAttrs) { if (sAttrs.hasOwnProperty(a)) { rAttrs[a] = rAttrs[a] || {}; Y.mix(rAttrs[a], sAttrs[a], true); } } } } }, aggregates : ["_PLUG", "_UNPLUG"] }; }, '3.3.0' ,{requires:['base-base']});