API Docs for: 3.13.0
Show:

File: base/js/BaseCore.js

  1. /**
  2. * The base module provides the Base class, which objects requiring attribute and custom event support can extend.
  3. * The module also provides two ways to reuse code - It augments Base with the Plugin.Host interface which provides
  4. * plugin support and also provides the BaseCore.build method which provides a way to build custom classes using extensions.
  5. *
  6. * @module base
  7. */
  8.  
  9. /**
  10. * <p>The base-core module provides the BaseCore class, the lightest version of Base,
  11. * which provides Base's basic lifecycle management and ATTRS construction support,
  12. * but doesn't fire init/destroy or attribute change events.</p>
  13. *
  14. * <p>It mixes in AttributeCore, which is the lightest version of Attribute</p>
  15. *
  16. * @module base
  17. * @submodule base-core
  18. */
  19. var O = Y.Object,
  20. L = Y.Lang,
  21. DOT = ".",
  22. INITIALIZED = "initialized",
  23. DESTROYED = "destroyed",
  24. INITIALIZER = "initializer",
  25. VALUE = "value",
  26. OBJECT_CONSTRUCTOR = Object.prototype.constructor,
  27. DEEP = "deep",
  28. SHALLOW = "shallow",
  29. DESTRUCTOR = "destructor",
  30.  
  31. AttributeCore = Y.AttributeCore,
  32.  
  33. _wlmix = function(r, s, wlhash) {
  34. var p;
  35. for (p in s) {
  36. if(wlhash[p]) {
  37. r[p] = s[p];
  38. }
  39. }
  40. return r;
  41. };
  42.  
  43. /**
  44. * The BaseCore class, is the lightest version of Base, and provides Base's
  45. * basic lifecycle management and ATTRS construction support, but doesn't
  46. * fire init/destroy or attribute change events.
  47. *
  48. * BaseCore also handles the chaining of initializer and destructor methods across
  49. * the hierarchy as part of object construction and destruction. Additionally, attributes
  50. * configured through the static <a href="#property_BaseCore.ATTRS">ATTRS</a>
  51. * property for each class in the hierarchy will be initialized by BaseCore.
  52. *
  53. * Classes which require attribute support, but don't intend to use/expose attribute
  54. * change events can extend BaseCore instead of Base for optimal kweight and
  55. * runtime performance.
  56. *
  57. * **3.11.0 BACK COMPAT NOTE FOR COMPONENT DEVELOPERS**
  58. *
  59. * Prior to version 3.11.0, ATTRS would get added a class at a time. That is:
  60. *
  61. * <pre>
  62. * for each (class in the hierarchy) {
  63. * Call the class Extension constructors.
  64. *
  65. * Add the class ATTRS.
  66. *
  67. * Call the class initializer
  68. * Call the class Extension initializers.
  69. * }
  70. * </pre>
  71. *
  72. * As of 3.11.0, ATTRS from all classes in the hierarchy are added in one `addAttrs` call
  73. * before **any** initializers are called. That is, the flow becomes:
  74. *
  75. * <pre>
  76. * for each (class in the hierarchy) {
  77. * Call the class Extension constructors.
  78. * }
  79. *
  80. * Add ATTRS for all classes
  81. *
  82. * for each (class in the hierarchy) {
  83. * Call the class initializer.
  84. * Call the class Extension initializers.
  85. * }
  86. * </pre>
  87. *
  88. * Adding all ATTRS at once fixes subtle edge-case issues with subclass ATTRS overriding
  89. * superclass `setter`, `getter` or `valueFn` definitions and being unable to get/set attributes
  90. * defined by the subclass. It also leaves us with a cleaner order of operation flow moving
  91. * forward.
  92. *
  93. * However, it may require component developers to upgrade their components, for the following
  94. * scenarios:
  95. *
  96. * 1. It impacts components which may have `setter`, `getter` or `valueFn` code which
  97. * expects a superclass' initializer to have run.
  98. *
  99. * This is expected to be rare, but to support it, Base now supports a `_preAddAttrs()`, method
  100. * hook (same signature as `addAttrs`). Components can implement this method on their prototype
  101. * for edge cases which do require finer control over the order in which attributes are added
  102. * (see widget-htmlparser for example).
  103. *
  104. * 2. Extension developers may need to move code from Extension constructors to `initializer`s
  105. *
  106. * Older extensions, which were written before `initializer` support was added, had a lot of
  107. * initialization code in their constructors. For example, code which acccessed superclass
  108. * attributes. With the new flow this code would not be able to see attributes. The recommendation
  109. * is to move this initialization code to an `initializer` on the Extension, which was the
  110. * recommendation for anything created after `initializer` support for Extensions was added.
  111. *
  112. * @class BaseCore
  113. * @constructor
  114. * @uses AttributeCore
  115. * @param {Object} cfg Object with configuration property name/value pairs.
  116. * The object can be used to provide initial values for the objects published
  117. * attributes.
  118. */
  119. function BaseCore(cfg) {
  120. if (!this._BaseInvoked) {
  121. this._BaseInvoked = true;
  122.  
  123. Y.log('constructor called', 'life', 'base');
  124. this._initBase(cfg);
  125. }
  126. else { Y.log('Based constructor called more than once. Ignoring duplicate calls', 'life', 'base'); }
  127. }
  128.  
  129. /**
  130. * The list of properties which can be configured for each attribute
  131. * (e.g. setter, getter, writeOnce, readOnly etc.)
  132. *
  133. * @property _ATTR_CFG
  134. * @type Array
  135. * @static
  136. * @private
  137. */
  138. BaseCore._ATTR_CFG = AttributeCore._ATTR_CFG.concat("cloneDefaultValue");
  139.  
  140. /**
  141. * The array of non-attribute configuration properties supported by this class.
  142. *
  143. * For example `BaseCore` defines a "plugins" configuration property which
  144. * should not be set up as an attribute. This property is primarily required so
  145. * that when <a href="#property__allowAdHocAttrs">`_allowAdHocAttrs`</a> is enabled by a class,
  146. * non-attribute configuration properties don't get added as ad-hoc attributes.
  147. *
  148. * @property _NON_ATTRS_CFG
  149. * @type Array
  150. * @static
  151. * @private
  152. */
  153. BaseCore._NON_ATTRS_CFG = ["plugins"];
  154.  
  155. /**
  156. * This property controls whether or not instances of this class should
  157. * allow users to add ad-hoc attributes through the constructor configuration
  158. * hash.
  159. *
  160. * AdHoc attributes are attributes which are not defined by the class, and are
  161. * not handled by the MyClass._NON_ATTRS_CFG
  162. *
  163. * @property _allowAdHocAttrs
  164. * @type boolean
  165. * @default undefined (false)
  166. * @protected
  167. */
  168.  
  169. /**
  170. * The string to be used to identify instances of this class.
  171. *
  172. * Classes extending BaseCore, should define their own
  173. * static NAME property, which should be camelCase by
  174. * convention (e.g. MyClass.NAME = "myClass";).
  175. *
  176. * @property NAME
  177. * @type String
  178. * @static
  179. */
  180. BaseCore.NAME = "baseCore";
  181.  
  182. /**
  183. * The default set of attributes which will be available for instances of this class, and
  184. * their configuration. In addition to the configuration properties listed by
  185. * AttributeCore's <a href="AttributeCore.html#method_addAttr">addAttr</a> method,
  186. * the attribute can also be configured with a "cloneDefaultValue" property, which
  187. * defines how the statically defined value field should be protected
  188. * ("shallow", "deep" and false are supported values).
  189. *
  190. * By default if the value is an object literal or an array it will be "shallow"
  191. * cloned, to protect the default value.
  192. *
  193. * @property ATTRS
  194. * @type Object
  195. * @static
  196. */
  197. BaseCore.ATTRS = {
  198. /**
  199. * Flag indicating whether or not this object
  200. * has been through the init lifecycle phase.
  201. *
  202. * @attribute initialized
  203. * @readonly
  204. * @default false
  205. * @type boolean
  206. */
  207. initialized: {
  208. readOnly:true,
  209. value:false
  210. },
  211.  
  212. /**
  213. * Flag indicating whether or not this object
  214. * has been through the destroy lifecycle phase.
  215. *
  216. * @attribute destroyed
  217. * @readonly
  218. * @default false
  219. * @type boolean
  220. */
  221. destroyed: {
  222. readOnly:true,
  223. value:false
  224. }
  225. };
  226.  
  227. /**
  228. Provides a way to safely modify a `Y.BaseCore` subclass' static `ATTRS`
  229. after the class has been defined or created.
  230.  
  231. BaseCore-based classes cache information about the class hierarchy in order
  232. to efficiently create instances. This cache includes includes the aggregated
  233. `ATTRS` configs. If the static `ATTRS` configs need to be modified after the
  234. class has been defined or create, then use this method which will make sure
  235. to clear any cached data before making any modifications.
  236.  
  237. @method modifyAttrs
  238. @param {Function} [ctor] The constructor function whose `ATTRS` should be
  239. modified. If a `ctor` function is not specified, then `this` is assumed
  240. to be the constructor which hosts the `ATTRS`.
  241. @param {Object} configs The collection of `ATTRS` configs to mix with the
  242. existing attribute configurations.
  243. @static
  244. @since 3.10.0
  245. **/
  246. BaseCore.modifyAttrs = function (ctor, configs) {
  247. // When called without a constructor, assume `this` is the constructor.
  248. if (typeof ctor !== 'function') {
  249. configs = ctor;
  250. ctor = this;
  251. }
  252.  
  253. var attrs, attr, name;
  254.  
  255. // Eagerly create the `ATTRS` object if it doesn't already exist.
  256. attrs = ctor.ATTRS || (ctor.ATTRS = {});
  257.  
  258. if (configs) {
  259. // Clear cache because it has ATTRS aggregation data which is about
  260. // to be modified.
  261. ctor._CACHED_CLASS_DATA = null;
  262.  
  263. for (name in configs) {
  264. if (configs.hasOwnProperty(name)) {
  265. attr = attrs[name] || (attrs[name] = {});
  266. Y.mix(attr, configs[name], true);
  267. }
  268. }
  269. }
  270. };
  271.  
  272. BaseCore.prototype = {
  273.  
  274. /**
  275. * Internal construction logic for BaseCore.
  276. *
  277. * @method _initBase
  278. * @param {Object} config The constructor configuration object
  279. * @private
  280. */
  281. _initBase : function(config) {
  282. Y.log('init called', 'life', 'base');
  283.  
  284. Y.stamp(this);
  285.  
  286. this._initAttribute(config);
  287.  
  288. // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
  289. // initial state, but don't initialize Plugins yet. That's done after initialization.
  290. var PluginHost = Y.Plugin && Y.Plugin.Host;
  291. if (this._initPlugins && PluginHost) {
  292. PluginHost.call(this);
  293. }
  294.  
  295. if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
  296.  
  297. /**
  298. * The string used to identify the class of this object.
  299. *
  300. * @deprecated Use this.constructor.NAME
  301. * @property name
  302. * @type String
  303. */
  304. this.name = this.constructor.NAME;
  305.  
  306. this.init.apply(this, arguments);
  307. },
  308.  
  309. /**
  310. * Initializes AttributeCore
  311. *
  312. * @method _initAttribute
  313. * @private
  314. */
  315. _initAttribute: function() {
  316. AttributeCore.call(this);
  317. },
  318.  
  319. /**
  320. * Init lifecycle method, invoked during construction. Sets up attributes
  321. * and invokes initializers for the class hierarchy.
  322. *
  323. * @method init
  324. * @chainable
  325. * @param {Object} cfg Object with configuration property name/value pairs
  326. * @return {BaseCore} A reference to this object
  327. */
  328. init: function(cfg) {
  329. Y.log('init called', 'life', 'base');
  330.  
  331. this._baseInit(cfg);
  332.  
  333. return this;
  334. },
  335.  
  336. /**
  337. * Internal initialization implementation for BaseCore
  338. *
  339. * @method _baseInit
  340. * @private
  341. */
  342. _baseInit: function(cfg) {
  343. this._initHierarchy(cfg);
  344.  
  345. if (this._initPlugins) {
  346. // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
  347. this._initPlugins(cfg);
  348. }
  349. this._set(INITIALIZED, true);
  350. },
  351.  
  352. /**
  353. * Destroy lifecycle method. Invokes destructors for the class hierarchy.
  354. *
  355. * @method destroy
  356. * @return {BaseCore} A reference to this object
  357. * @chainable
  358. */
  359. destroy: function() {
  360. this._baseDestroy();
  361. return this;
  362. },
  363.  
  364. /**
  365. * Internal destroy implementation for BaseCore
  366. *
  367. * @method _baseDestroy
  368. * @private
  369. */
  370. _baseDestroy : function() {
  371. if (this._destroyPlugins) {
  372. this._destroyPlugins();
  373. }
  374. this._destroyHierarchy();
  375. this._set(DESTROYED, true);
  376. },
  377.  
  378. /**
  379. * Returns the class hierarchy for this object, with BaseCore being the last class in the array.
  380. *
  381. * @method _getClasses
  382. * @protected
  383. * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
  384. * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the
  385. * cached value.
  386. */
  387. _getClasses : function() {
  388. if (!this._classes) {
  389. this._initHierarchyData();
  390. }
  391. return this._classes;
  392. },
  393.  
  394. /**
  395. * Returns an aggregated set of attribute configurations, by traversing
  396. * the class hierarchy.
  397. *
  398. * @method _getAttrCfgs
  399. * @protected
  400. * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
  401. * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
  402. * the cached value.
  403. */
  404. _getAttrCfgs : function() {
  405. if (!this._attrs) {
  406. this._initHierarchyData();
  407. }
  408. return this._attrs;
  409. },
  410.  
  411. /**
  412. * A helper method used to isolate the attrs config for this instance to pass to `addAttrs`,
  413. * from the static cached ATTRS for the class.
  414. *
  415. * @method _getInstanceAttrCfgs
  416. * @private
  417. *
  418. * @param {Object} allCfgs The set of all attribute configurations for this instance.
  419. * Attributes will be removed from this set, if they belong to the filtered class, so
  420. * that by the time all classes are processed, allCfgs will be empty.
  421. *
  422. * @return {Object} The set of attributes to be added for this instance, suitable
  423. * for passing through to `addAttrs`.
  424. */
  425. _getInstanceAttrCfgs : function(allCfgs) {
  426.  
  427. var cfgs = {},
  428. cfg,
  429. val,
  430. subAttr,
  431. subAttrs,
  432. subAttrPath,
  433. attr,
  434. attrCfg,
  435. allSubAttrs = allCfgs._subAttrs,
  436. attrCfgProperties = this._attrCfgHash();
  437.  
  438. for (attr in allCfgs) {
  439.  
  440. if (allCfgs.hasOwnProperty(attr) && attr !== "_subAttrs") {
  441.  
  442. attrCfg = allCfgs[attr];
  443.  
  444. // Need to isolate from allCfgs, because we're going to set values etc.
  445. cfg = cfgs[attr] = _wlmix({}, attrCfg, attrCfgProperties);
  446.  
  447. val = cfg.value;
  448.  
  449. if (val && (typeof val === "object")) {
  450. this._cloneDefaultValue(attr, cfg);
  451. }
  452.  
  453. if (allSubAttrs && allSubAttrs.hasOwnProperty(attr)) {
  454. subAttrs = allCfgs._subAttrs[attr];
  455.  
  456. for (subAttrPath in subAttrs) {
  457. subAttr = subAttrs[subAttrPath];
  458.  
  459. if (subAttr.path) {
  460. O.setValue(cfg.value, subAttr.path, subAttr.value);
  461. }
  462. }
  463. }
  464. }
  465. }
  466.  
  467. return cfgs;
  468. },
  469.  
  470. /**
  471. * @method _filterAdHocAttrs
  472. * @private
  473. *
  474. * @param {Object} allAttrs The set of all attribute configurations for this instance.
  475. * Attributes will be removed from this set, if they belong to the filtered class, so
  476. * that by the time all classes are processed, allCfgs will be empty.
  477. * @param {Object} userVals The config object passed in by the user, from which adhoc attrs are to be filtered.
  478. * @return {Object} The set of adhoc attributes passed in, in the form
  479. * of an object with attribute name/configuration pairs.
  480. */
  481. _filterAdHocAttrs : function(allAttrs, userVals) {
  482. var adHocs,
  483. nonAttrs = this._nonAttrs,
  484. attr;
  485.  
  486. if (userVals) {
  487. adHocs = {};
  488. for (attr in userVals) {
  489. if (!allAttrs[attr] && !nonAttrs[attr] && userVals.hasOwnProperty(attr)) {
  490. adHocs[attr] = {
  491. value:userVals[attr]
  492. };
  493. }
  494. }
  495. }
  496.  
  497. return adHocs;
  498. },
  499.  
  500. /**
  501. * A helper method used by _getClasses and _getAttrCfgs, which determines both
  502. * the array of classes and aggregate set of attribute configurations
  503. * across the class hierarchy for the instance.
  504. *
  505. * @method _initHierarchyData
  506. * @private
  507. */
  508. _initHierarchyData : function() {
  509.  
  510. var ctor = this.constructor,
  511. cachedClassData = ctor._CACHED_CLASS_DATA,
  512. c,
  513. i,
  514. l,
  515. attrCfg,
  516. attrCfgHash,
  517. needsAttrCfgHash = !ctor._ATTR_CFG_HASH,
  518. nonAttrsCfg,
  519. nonAttrs = {},
  520. classes = [],
  521. attrs = [];
  522.  
  523. // Start with `this` instance's constructor.
  524. c = ctor;
  525.  
  526. if (!cachedClassData) {
  527.  
  528. while (c) {
  529. // Add to classes
  530. classes[classes.length] = c;
  531.  
  532. // Add to attributes
  533. if (c.ATTRS) {
  534. attrs[attrs.length] = c.ATTRS;
  535. }
  536.  
  537. // Aggregate ATTR cfg whitelist.
  538. if (needsAttrCfgHash) {
  539. attrCfg = c._ATTR_CFG;
  540. attrCfgHash = attrCfgHash || {};
  541.  
  542. if (attrCfg) {
  543. for (i = 0, l = attrCfg.length; i < l; i += 1) {
  544. attrCfgHash[attrCfg[i]] = true;
  545. }
  546. }
  547. }
  548.  
  549. // Commenting out the if. We always aggregate, since we don't
  550. // know if we'll be needing this on the instance or not.
  551. // if (this._allowAdHocAttrs) {
  552. nonAttrsCfg = c._NON_ATTRS_CFG;
  553. if (nonAttrsCfg) {
  554. for (i = 0, l = nonAttrsCfg.length; i < l; i++) {
  555. nonAttrs[nonAttrsCfg[i]] = true;
  556. }
  557. }
  558. //}
  559.  
  560. c = c.superclass ? c.superclass.constructor : null;
  561. }
  562.  
  563. // Cache computed `_ATTR_CFG_HASH` on the constructor.
  564. if (needsAttrCfgHash) {
  565. ctor._ATTR_CFG_HASH = attrCfgHash;
  566. }
  567.  
  568. cachedClassData = ctor._CACHED_CLASS_DATA = {
  569. classes : classes,
  570. nonAttrs : nonAttrs,
  571. attrs : this._aggregateAttrs(attrs)
  572. };
  573.  
  574. }
  575.  
  576. this._classes = cachedClassData.classes;
  577. this._attrs = cachedClassData.attrs;
  578. this._nonAttrs = cachedClassData.nonAttrs;
  579. },
  580.  
  581. /**
  582. * Utility method to define the attribute hash used to filter/whitelist property mixes for
  583. * this class for iteration performance reasons.
  584. *
  585. * @method _attrCfgHash
  586. * @private
  587. */
  588. _attrCfgHash: function() {
  589. return this.constructor._ATTR_CFG_HASH;
  590. },
  591.  
  592. /**
  593. * This method assumes that the value has already been checked to be an object.
  594. * Since it's on a critical path, we don't want to re-do the check.
  595. *
  596. * @method _cloneDefaultValue
  597. * @param {Object} cfg
  598. * @private
  599. */
  600. _cloneDefaultValue : function(attr, cfg) {
  601.  
  602. var val = cfg.value,
  603. clone = cfg.cloneDefaultValue;
  604.  
  605. if (clone === DEEP || clone === true) {
  606. Y.log('Cloning default value for attribute:' + attr, 'info', 'base');
  607. cfg.value = Y.clone(val);
  608. } else if (clone === SHALLOW) {
  609. Y.log('Merging default value for attribute:' + attr, 'info', 'base');
  610. cfg.value = Y.merge(val);
  611. } else if ((clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val)))) {
  612. cfg.value = Y.clone(val);
  613. }
  614. // else if (clone === false), don't clone the static default value.
  615. // It's intended to be used by reference.
  616. },
  617.  
  618. /**
  619. * A helper method, used by _initHierarchyData to aggregate
  620. * attribute configuration across the instances class hierarchy.
  621. *
  622. * The method will protect the attribute configuration value to protect the statically defined
  623. * default value in ATTRS if required (if the value is an object literal, array or the
  624. * attribute configuration has cloneDefaultValue set to shallow or deep).
  625. *
  626. * @method _aggregateAttrs
  627. * @private
  628. * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy
  629. * (subclass first, Base last)
  630. * @return {Object} The aggregate set of ATTRS definitions for the instance
  631. */
  632. _aggregateAttrs : function(allAttrs) {
  633.  
  634. var attr,
  635. attrs,
  636. subAttrsHash,
  637. cfg,
  638. path,
  639. i,
  640. cfgPropsHash = this._attrCfgHash(),
  641. aggAttr,
  642. aggAttrs = {};
  643.  
  644. if (allAttrs) {
  645. for (i = allAttrs.length-1; i >= 0; --i) {
  646.  
  647. attrs = allAttrs[i];
  648.  
  649. for (attr in attrs) {
  650. if (attrs.hasOwnProperty(attr)) {
  651.  
  652. // PERF TODO: Do we need to merge here, since we're merging later in getInstanceAttrCfgs
  653. // Should we move this down to only merge if we hit the path or valueFn ifs below?
  654. cfg = _wlmix({}, attrs[attr], cfgPropsHash);
  655.  
  656. path = null;
  657. if (attr.indexOf(DOT) !== -1) {
  658. path = attr.split(DOT);
  659. attr = path.shift();
  660. }
  661.  
  662. aggAttr = aggAttrs[attr];
  663.  
  664. if (path && aggAttr && aggAttr.value) {
  665.  
  666. subAttrsHash = aggAttrs._subAttrs;
  667.  
  668. if (!subAttrsHash) {
  669. subAttrsHash = aggAttrs._subAttrs = {};
  670. }
  671.  
  672. if (!subAttrsHash[attr]) {
  673. subAttrsHash[attr] = {};
  674. }
  675.  
  676. subAttrsHash[attr][path.join(DOT)] = {
  677. value: cfg.value,
  678. path : path
  679. };
  680.  
  681. } else if (!path) {
  682.  
  683. if (!aggAttr) {
  684. aggAttrs[attr] = cfg;
  685. } else {
  686. if (aggAttr.valueFn && VALUE in cfg) {
  687. aggAttr.valueFn = null;
  688. }
  689.  
  690. // Mix into existing config.
  691. _wlmix(aggAttr, cfg, cfgPropsHash);
  692. }
  693. }
  694. }
  695. }
  696. }
  697. }
  698.  
  699. return aggAttrs;
  700. },
  701.  
  702. /**
  703. * Initializes the class hierarchy for the instance, which includes
  704. * initializing attributes for each class defined in the class's
  705. * static <a href="#property_BaseCore.ATTRS">ATTRS</a> property and
  706. * invoking the initializer method on the prototype of each class in the hierarchy.
  707. *
  708. * @method _initHierarchy
  709. * @param {Object} userVals Object with configuration property name/value pairs
  710. * @private
  711. */
  712. _initHierarchy : function(userVals) {
  713.  
  714. var lazy = this._lazyAddAttrs,
  715. constr,
  716. constrProto,
  717. i,
  718. l,
  719. ci,
  720. ei,
  721. el,
  722. ext,
  723. extProto,
  724. exts,
  725. instanceAttrs,
  726. initializers = [],
  727. classes = this._getClasses(),
  728. attrCfgs = this._getAttrCfgs(),
  729. cl = classes.length - 1;
  730.  
  731. // Constructors
  732. for (ci = cl; ci >= 0; ci--) {
  733.  
  734. constr = classes[ci];
  735. constrProto = constr.prototype;
  736. exts = constr._yuibuild && constr._yuibuild.exts;
  737.  
  738. // Using INITIALIZER in hasOwnProperty check, for performance reasons (helps IE6 avoid GC thresholds when
  739. // referencing string literals). Not using it in apply, again, for performance "." is faster.
  740.  
  741. if (constrProto.hasOwnProperty(INITIALIZER)) {
  742. // Store initializer while we're here and looping
  743. initializers[initializers.length] = constrProto.initializer;
  744. }
  745.  
  746. if (exts) {
  747. for (ei = 0, el = exts.length; ei < el; ei++) {
  748.  
  749. ext = exts[ei];
  750.  
  751. // Ext Constructor
  752. ext.apply(this, arguments);
  753.  
  754. extProto = ext.prototype;
  755. if (extProto.hasOwnProperty(INITIALIZER)) {
  756. // Store initializer while we're here and looping
  757. initializers[initializers.length] = extProto.initializer;
  758. }
  759. }
  760. }
  761. }
  762.  
  763. // ATTRS
  764. instanceAttrs = this._getInstanceAttrCfgs(attrCfgs);
  765.  
  766. if (this._preAddAttrs) {
  767. this._preAddAttrs(instanceAttrs, userVals, lazy);
  768. }
  769.  
  770. if (this._allowAdHocAttrs) {
  771. this.addAttrs(this._filterAdHocAttrs(attrCfgs, userVals), userVals, lazy);
  772. }
  773.  
  774. this.addAttrs(instanceAttrs, userVals, lazy);
  775.  
  776. // Initializers
  777. for (i = 0, l = initializers.length; i < l; i++) {
  778. initializers[i].apply(this, arguments);
  779. }
  780. },
  781.  
  782. /**
  783. * Destroys the class hierarchy for this instance by invoking
  784. * the destructor method on the prototype of each class in the hierarchy.
  785. *
  786. * @method _destroyHierarchy
  787. * @private
  788. */
  789. _destroyHierarchy : function() {
  790. var constr,
  791. constrProto,
  792. ci, cl, ei, el, exts, extProto,
  793. classes = this._getClasses();
  794.  
  795. for (ci = 0, cl = classes.length; ci < cl; ci++) {
  796. constr = classes[ci];
  797. constrProto = constr.prototype;
  798. exts = constr._yuibuild && constr._yuibuild.exts;
  799.  
  800. if (exts) {
  801. for (ei = 0, el = exts.length; ei < el; ei++) {
  802. extProto = exts[ei].prototype;
  803. if (extProto.hasOwnProperty(DESTRUCTOR)) {
  804. extProto.destructor.apply(this, arguments);
  805. }
  806. }
  807. }
  808.  
  809. if (constrProto.hasOwnProperty(DESTRUCTOR)) {
  810. constrProto.destructor.apply(this, arguments);
  811. }
  812. }
  813. },
  814.  
  815. /**
  816. * Default toString implementation. Provides the constructor NAME
  817. * and the instance guid, if set.
  818. *
  819. * @method toString
  820. * @return {String} String representation for this object
  821. */
  822. toString: function() {
  823. return this.name + "[" + Y.stamp(this, true) + "]";
  824. }
  825. };
  826.  
  827. // Straightup augment, no wrapper functions
  828. Y.mix(BaseCore, AttributeCore, false, null, 1);
  829.  
  830. // Fix constructor
  831. BaseCore.prototype.constructor = BaseCore;
  832.  
  833. Y.BaseCore = BaseCore;
  834.