]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/base/base-base.js
Release 6.2.0beta4
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / base / base-base.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 3.0.0
6 build: 1549
7 */
8 YUI.add('base-base', function(Y) {
9
10     /**
11      * The base module provides the Base class, which objects requiring attribute and custom event support can extend. 
12      * The module also provides two ways to reuse code - An augmentable Plugin.Host interface which provides plugin support 
13      * (which is augmented to the Base class) and Base.build which provides a way to 
14      * build custom classes using extensions.
15      *
16      * @module base
17      */
18
19     /**
20      * The base-base submodule provides the Base class without the Plugin support, provided by Plugin.Host, 
21      * and without the extension support provided by Base.build.
22      *
23      * @module base
24      * @submodule base-base
25      */
26     var O = Y.Object,
27         L = Y.Lang,
28         DOT = ".",
29         DESTROY = "destroy",
30         INIT = "init",
31         INITIALIZED = "initialized",
32         DESTROYED = "destroyed",
33         INITIALIZER = "initializer",
34         OBJECT_CONSTRUCTOR = Object.prototype.constructor,
35         DEEP = "deep",
36         SHALLOW = "shallow",
37         DESTRUCTOR = "destructor",
38
39         Attribute = Y.Attribute;
40
41     /**
42      * <p>
43      * A base class which objects requiring attributes and custom event support can 
44      * extend. Base also handles the chaining of initializer and destructor methods across 
45      * the hierarchy as part of object construction and destruction. Additionally, attributes configured 
46      * through the static <a href="#property_Base.ATTRS">ATTRS</a> property for each class 
47      * in the hierarchy will be initialized by Base.
48      * </p>
49      *
50      * <p>
51      * The static <a href="#property_Base.NAME">NAME</a> property of each class extending 
52      * from Base will be used as the identifier for the class, and is used by Base to prefix 
53      * all events fired by instances of that class.
54      * </p>
55      * @class Base
56      * @constructor
57      * @uses Attribute
58      * @uses Plugin.Host
59      *
60      * @param {Object} config Object with configuration property name/value pairs
61      */
62     function Base() {
63
64         Attribute.call(this);
65
66         // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
67         // initial state, but don't initialize Plugins yet. That's done after initialization.
68         var PluginHost = Y.Plugin && Y.Plugin.Host;  
69         if (this._initPlugins && PluginHost) {
70             PluginHost.call(this);
71         }
72
73         if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
74
75         this.init.apply(this, arguments);
76     }
77
78     /**
79      * The list of properties which can be configured for 
80      * each attribute (e.g. setter, getter, writeOnce, readOnly etc.)
81      *
82      * @property Base._ATTR_CFG
83      * @type Array
84      * @static
85      * @private
86      */
87     Base._ATTR_CFG = Attribute._ATTR_CFG.concat("cloneDefaultValue");
88
89     /**
90      * <p>
91      * The string to be used to identify instances of 
92      * this class, for example in prefixing events.
93      * </p>
94      * <p>
95      * Classes extending Base, should define their own
96      * static NAME property, which should be camelCase by
97      * convention (e.g. MyClass.NAME = "myClass";).
98      * </p>
99      * @property Base.NAME
100      * @type String
101      * @static
102      */
103     Base.NAME = "base";
104
105     /**
106      * The default set of attributes which will be available for instances of this class, and 
107      * their configuration. In addition to the configuration properties listed by 
108      * Attribute's <a href="Attribute.html#method_addAttr">addAttr</a> method, the attribute 
109      * can also be configured with a "cloneDefaultValue" property, which defines how the statically
110      * defined value field should be protected ("shallow", "deep" and false are supported values). 
111      *
112      * By default if the value is an object literal or an array it will be "shallow" cloned, to 
113      * protect the default value.
114      *
115      * @property Base.ATTRS
116      * @type Object
117      * @static
118      */
119     Base.ATTRS = {
120         /**
121          * Flag indicating whether or not this object
122          * has been through the init lifecycle phase.
123          *
124          * @attribute initialized
125          * @readonly
126          * @default false
127          * @type boolean
128          */
129         initialized: {
130             readOnly:true,
131             value:false
132         },
133
134         /**
135          * Flag indicating whether or not this object
136          * has been through the destroy lifecycle phase.
137          *
138          * @attribute destroyed
139          * @readonly
140          * @default false
141          * @type boolean
142          */
143         destroyed: {
144             readOnly:true,
145             value:false
146         }
147     };
148
149     Base.prototype = {
150
151         /**
152          * Init lifecycle method, invoked during construction.
153          * Fires the init event prior to setting up attributes and 
154          * invoking initializers for the class hierarchy.
155          *
156          * @method init
157          * @final
158          * @chainable
159          * @param {Object} config Object with configuration property name/value pairs
160          * @return {Base} A reference to this object
161          */
162         init: function(config) {
163
164             /**
165              * The string used to identify the class of this object.
166              *
167              * @deprecated Use this.constructor.NAME
168              * @property name
169              * @type String
170              */
171             this._yuievt.config.prefix = this.name = this.constructor.NAME;
172
173             /**
174              * <p>
175              * Lifecycle event for the init phase, fired prior to initialization. 
176              * Invoking the preventDefault() method on the event object provided 
177              * to subscribers will prevent initialization from occuring.
178              * </p>
179              * <p>
180              * Subscribers to the "after" momemt of this event, will be notified
181              * after initialization of the object is complete (and therefore
182              * cannot prevent initialization).
183              * </p>
184              *
185              * @event init
186              * @preventable _defInitFn
187              * @param {EventFacade} e Event object, with a cfg property which 
188              * refers to the configuration object passed to the constructor.
189              */
190             this.publish(INIT, {
191                 queuable:false,
192                 defaultFn:this._defInitFn
193             });
194
195             if (config) {
196                 if (config.on) {
197                     this.on(config.on);
198                 }
199                 if (config.after) {
200                     this.after(config.after);
201                 }
202             }
203
204             this.fire(INIT, {cfg: config});
205
206             return this;
207         },
208
209         /**
210          * <p>
211          * Destroy lifecycle method. Fires the destroy
212          * event, prior to invoking destructors for the
213          * class hierarchy.
214          * </p>
215          * <p>
216          * Subscribers to the destroy
217          * event can invoke preventDefault on the event object, to prevent destruction
218          * from proceeding.
219          * </p>
220          * @method destroy
221          * @return {Base} A reference to this object
222          * @final
223          * @chainable
224          */
225         destroy: function() {
226
227             /**
228              * <p>
229              * Lifecycle event for the destroy phase, 
230              * fired prior to destruction. Invoking the preventDefault 
231              * method on the event object provided to subscribers will 
232              * prevent destruction from proceeding.
233              * </p>
234              * <p>
235              * Subscribers to the "after" moment of this event, will be notified
236              * after destruction is complete (and as a result cannot prevent
237              * destruction).
238              * </p>
239              * @event destroy
240              * @preventable _defDestroyFn
241              * @param {EventFacade} e Event object
242              */
243             this.publish(DESTROY, {
244                 queuable:false,
245                 defaultFn: this._defDestroyFn
246             });
247             this.fire(DESTROY);
248             return this;
249         },
250
251         /**
252          * Default init event handler
253          *
254          * @method _defInitFn
255          * @param {EventFacade} e Event object, with a cfg property which 
256          * refers to the configuration object passed to the constructor.
257          * @protected
258          */
259         _defInitFn : function(e) {
260             this._initHierarchy(e.cfg);
261             if (this._initPlugins) {
262                 // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
263                 this._initPlugins(e.cfg);
264             }
265             this._set(INITIALIZED, true);
266         },
267
268         /**
269          * Default destroy event handler
270          *
271          * @method _defDestroyFn
272          * @param {EventFacade} e Event object
273          * @protected
274          */
275         _defDestroyFn : function(e) {
276             this._destroyHierarchy();
277             if (this._destroyPlugins) {
278                 this._destroyPlugins();
279             }
280             this._set(DESTROYED, true);
281         },
282
283         /**
284          * Returns the class hierarchy for this object, with Base being the last class in the array.
285          *
286          * @method _getClasses
287          * @protected
288          * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
289          * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the 
290          * cached value.
291          */
292         _getClasses : function() {
293             if (!this._classes) {
294                 this._initHierarchyData();
295             }
296             return this._classes;
297         },
298
299         /**
300          * Returns an aggregated set of attribute configurations, by traversing the class hierarchy.
301          *
302          * @method _getAttrCfgs
303          * @protected
304          * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
305          * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
306          * the cached value.
307          */
308         _getAttrCfgs : function() {
309             if (!this._attrs) {
310                 this._initHierarchyData();
311             }
312             return this._attrs;
313         },
314
315         /**
316          * A helper method used when processing ATTRS across the class hierarchy during 
317          * initialization. Returns a disposable object with the attributes defined for 
318          * the provided class, extracted from the set of all attributes passed in .
319          *
320          * @method _filterAttrCfs
321          * @private
322          *
323          * @param {Function} clazz The class for which the desired attributes are required.
324          * @param {Object} allCfgs The set of all attribute configurations for this instance. 
325          * Attributes will be removed from this set, if they belong to the filtered class, so
326          * that by the time all classes are processed, allCfgs will be empty.
327          * 
328          * @return {Object} The set of attributes belonging to the class passed in, in the form
329          * of an object with attribute name/configuration pairs.
330          */
331         _filterAttrCfgs : function(clazz, allCfgs) {
332             var cfgs = null, attr, attrs = clazz.ATTRS;
333
334             if (attrs) {
335                 for (attr in attrs) {
336                     if (attrs.hasOwnProperty(attr) && allCfgs[attr]) {
337                         cfgs = cfgs || {};
338                         cfgs[attr] = allCfgs[attr];
339                         delete allCfgs[attr];
340                     }
341                 }
342             }
343
344             return cfgs;
345         },
346
347         /**
348          * A helper method used by _getClasses and _getAttrCfgs, which determines both
349          * the array of classes and aggregate set of attribute configurations
350          * across the class hierarchy for the instance.
351          * 
352          * @method _initHierarchyData
353          * @private
354          */
355         _initHierarchyData : function() {
356             var c = this.constructor, 
357                 classes = [],
358                 attrs = [];
359
360             while (c) {
361                 // Add to classes
362                 classes[classes.length] = c;
363
364                 // Add to attributes
365                 if (c.ATTRS) {
366                     attrs[attrs.length] = c.ATTRS;
367                 }
368                 c = c.superclass ? c.superclass.constructor : null;
369             }
370
371             this._classes = classes;
372             this._attrs = this._aggregateAttrs(attrs);
373         },
374
375         /**
376          * A helper method, used by _initHierarchyData to aggregate 
377          * attribute configuration across the instances class hierarchy.
378          *
379          * The method will potect the attribute configuration value to protect the statically defined 
380          * default value in ATTRS if required (if the value is an object literal, array or the 
381          * attribute configuration has cloneDefaultValue set to shallow or deep).
382          *
383          * @method _aggregateAttrs
384          * @private
385          * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy 
386          * (subclass first, Base last)
387          * @return {Object} The aggregate set of ATTRS definitions for the instance
388          */
389         _aggregateAttrs : function(allAttrs) {
390             var attr,
391                 attrs,
392                 cfg,
393                 val,
394                 path,
395                 i, 
396                 clone, 
397                 cfgProps = Base._ATTR_CFG,
398                 aggAttrs = {};
399
400             if (allAttrs) {
401                 for (i = allAttrs.length-1; i >= 0; --i) {
402                     attrs = allAttrs[i];
403
404                     for (attr in attrs) {
405                         if (attrs.hasOwnProperty(attr)) {
406
407                             // Protect config passed in
408                             cfg = Y.mix({}, attrs[attr], true, cfgProps);
409
410                             val = cfg.value;
411                             clone = cfg.cloneDefaultValue;
412
413                             if (val) {
414                                 if ( (clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val))) || clone === DEEP || clone === true) {
415                                     cfg.value = Y.clone(val);
416                                 } else if (clone === SHALLOW) {
417                                     cfg.value = Y.merge(val);
418                                 }
419                                 // else if (clone === false), don't clone the static default value. 
420                                 // It's intended to be used by reference.
421                             }
422
423                             path = null;
424                             if (attr.indexOf(DOT) !== -1) {
425                                 path = attr.split(DOT);
426                                 attr = path.shift();
427                             }
428
429                             if (path && aggAttrs[attr] && aggAttrs[attr].value) {
430                                 O.setValue(aggAttrs[attr].value, path, val);
431                             } else if (!path){
432                                 if (!aggAttrs[attr]) {
433                                     aggAttrs[attr] = cfg;
434                                 } else {
435                                     Y.mix(aggAttrs[attr], cfg, true, cfgProps);
436                                 }
437                             }
438                         }
439                     }
440                 }
441             }
442
443             return aggAttrs;
444         },
445
446         /**
447          * Initializes the class hierarchy for the instance, which includes 
448          * initializing attributes for each class defined in the class's 
449          * static <a href="#property_Base.ATTRS">ATTRS</a> property and 
450          * invoking the initializer method on the prototype of each class in the hierarchy.
451          *
452          * @method _initHierarchy
453          * @param {Object} userVals Object with configuration property name/value pairs
454          * @private
455          */
456         _initHierarchy : function(userVals) {
457             var lazy = this._lazyAddAttrs,
458                 constr,
459                 constrProto,
460                 ci,
461                 ei,
462                 el,
463                 classes = this._getClasses(),
464                 attrCfgs = this._getAttrCfgs();
465
466             for (ci = classes.length-1; ci >= 0; ci--) {
467
468                 constr = classes[ci];
469                 constrProto = constr.prototype;
470
471                 if (constr._yuibuild && constr._yuibuild.exts && !constr._yuibuild.dynamic) {
472                     for (ei = 0, el = constr._yuibuild.exts.length; ei < el; ei++) {
473                         constr._yuibuild.exts[ei].apply(this, arguments);
474                     }
475                 }
476
477                 this.addAttrs(this._filterAttrCfgs(constr, attrCfgs), userVals, lazy);
478
479                 if (constrProto.hasOwnProperty(INITIALIZER)) {
480                     constrProto.initializer.apply(this, arguments);
481                 }
482             }
483         },
484
485         /**
486          * Destroys the class hierarchy for this instance by invoking
487          * the descructor method on the prototype of each class in the hierarchy.
488          *
489          * @method _destroyHierarchy
490          * @private
491          */
492         _destroyHierarchy : function() {
493             var constr,
494                 constrProto,
495                 ci, cl,
496                 classes = this._getClasses();
497
498             for (ci = 0, cl = classes.length; ci < cl; ci++) {
499                 constr = classes[ci];
500                 constrProto = constr.prototype;
501                 if (constrProto.hasOwnProperty(DESTRUCTOR)) {
502                     constrProto.destructor.apply(this, arguments);
503                 }
504             }
505         },
506
507         /**
508          * Default toString implementation. Provides the constructor NAME
509          * and the instance ID.
510          *
511          * @method toString
512          * @return {String} String representation for this object
513          */
514         toString: function() {
515             return this.constructor.NAME + "[" + Y.stamp(this) + "]";
516         }
517     };
518
519     // Straightup augment, no wrapper functions
520     Y.mix(Base, Attribute, false, null, 1);
521
522     // Fix constructor
523     Base.prototype.constructor = Base;
524
525     Y.Base = Base;
526
527     // Fix constructor
528     Base.prototype.constructor = Base;
529
530
531 }, '3.0.0' ,{requires:['attribute-base']});