~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/static/javascript/yui/build/attribute/attribute-debug.js

[rs=mwhudson] Merged the latest and greatest from trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
 
3
Code licensed under the BSD License:
 
4
http://developer.yahoo.net/yui/license.txt
 
5
version: 3.0.0pr1
 
6
*/
 
7
YUI.add('attribute', function(Y) {
 
8
 
 
9
    /**
 
10
     * Managed Attribute Provider
 
11
     * @module attribute
 
12
     */
 
13
 
 
14
    /**
 
15
     * Maintain state for a collection of items.  Individual properties 
 
16
     * are stored in hash tables.  This is instead of having state objects 
 
17
     * for each item in the collection.  For large collections, especially 
 
18
     * changing ones, this approach may perform better.
 
19
     * 
 
20
     * @constructor
 
21
     * @class State
 
22
     */
 
23
    Y.State = function() { 
 
24
 
 
25
        /**
 
26
         * Hash of attributes
 
27
         * @property data
 
28
         */
 
29
        this.data = {};
 
30
    };
 
31
 
 
32
    Y.State.prototype = {
 
33
 
 
34
        /**
 
35
         * Add an item with all of the properties in the supplied object.
 
36
         * @method add
 
37
         * @param name {string} identifier for this attribute
 
38
         * @param o hash of attributes
 
39
         */
 
40
        add: function(name, o) {
 
41
            Y.each(o, function(v, k) {
 
42
                if (!this.data[k]) {
 
43
                    this.data[k] = {};
 
44
                }
 
45
 
 
46
                this.data[k][name] = v;
 
47
            }, this);
 
48
        },
 
49
 
 
50
        /**
 
51
         * Remove entire item, or optionally specified fields
 
52
         * @method remove
 
53
         * @param name {string} name of attribute
 
54
         * @param o {string|object|array} single key or collection of keys to delete
 
55
         */
 
56
        remove: function(name, o) {
 
57
            var d = this.data, 
 
58
                del = function(key) {
 
59
                    if (d[key] && (name in d[key])) {
 
60
                        delete d[key][name];
 
61
                    }
 
62
                };
 
63
 
 
64
            if (Y.Lang.isString(o)) {
 
65
                del(o);
 
66
            } else {
 
67
                Y.each(o || d, function(v, k) {
 
68
                    if(Y.Lang.isString(k)) {
 
69
                        del(k);
 
70
                    } else {
 
71
                        del(v);
 
72
                    }
 
73
                }, this);
 
74
 
 
75
            }
 
76
        },
 
77
 
 
78
        /**
 
79
         * For a given item, gets an attribute.  If key is not
 
80
         * supplied, a disposable object with all attributes is 
 
81
         * returned.  Use of the latter option makes sense when
 
82
         * working with single items, but not if object explosion
 
83
         * might cause gc problems.
 
84
         * @method get
 
85
         * @param name {string} name of attribute
 
86
         * @param key {string} optional attribute to get
 
87
         * @return either the value of the supplied key or an object with
 
88
         * all data.
 
89
         */
 
90
        // get: function(name, key, val) {
 
91
        get: function(name, key) {
 
92
            var d = this.data;
 
93
 
 
94
            if (key) {
 
95
                return (d[key] && name in d[key]) ?  d[key][name] : undefined;
 
96
            } else {
 
97
                var o = {};
 
98
 
 
99
                Y.each(d, function(v, k) {
 
100
                    if (name in d[k]) {
 
101
                        o[k] = v[name];
 
102
                    }
 
103
                }, this);
 
104
 
 
105
                return o;
 
106
 
 
107
            }
 
108
        }
 
109
 
 
110
        // figure out what kind of functionality we may need here
 
111
        // get whole list
 
112
        // get a list of items and values for a given key
 
113
        // get a list of items where a key has the supplied value
 
114
        /*
 
115
        list: function(key, val) {
 
116
            var o = {}, d = this.data, test = !L.isUndefined(val);
 
117
 
 
118
            Y.each(this, function(v, k) {
 
119
 
 
120
                // verify key
 
121
                if (key && k !== key) {
 
122
                    return;
 
123
                // verify value.  note, v will be the item names, so this
 
124
                // isn't working ... need to iterate v items
 
125
                } else if (test && v !== val) {
 
126
                    return;
 
127
                }
 
128
 
 
129
                o[k] = v;
 
130
 
 
131
            }, this);
 
132
 
 
133
            return o;
 
134
        }
 
135
        */
 
136
    };
 
137
 
 
138
    /**
 
139
     * Managed Attribute Provider
 
140
     * @module attribute
 
141
     */
 
142
 
 
143
    var O = Y.Object,
 
144
 
 
145
        DOT = ".",
 
146
        CHANGE = "Change",
 
147
        GET = "get",
 
148
        SET = "set",
 
149
        VALUE = "value",
 
150
        CLONE = "clone",
 
151
        READ_ONLY = "readOnly",
 
152
        WRITE_ONCE = "writeOnce",
 
153
        VALIDATOR = "validator",
 
154
 
 
155
        CLONE_ENUM;
 
156
 
 
157
    /**
 
158
     * <p>
 
159
     * Attribute provides managed attribute support. 
 
160
     * </p>
 
161
     * <p>
 
162
     * The class is designed to be augmented onto a host class, 
 
163
     * and allows the host to support get/set methods for attributes,
 
164
     * initial configuration support and attribute change events.
 
165
     * </p>
 
166
     * <p>Attributes added to the host can:</p>
 
167
     * <ul>
 
168
     *     <li>Be defined as read-only.</li>
 
169
     *     <li>Be defined as write-once.</li>
 
170
     *     <li>Be defined with a set function, used to manipulate
 
171
     *     values passed to Attribute's set method, before they are stored.</li>
 
172
     *     <li>Be defined with a validator function, to validate values before they are stored.</li>
 
173
     *     <li>Be defined with a get function, which can be used to manipulate stored values,
 
174
     *     before they are returned by Attribute's get method.</li>
 
175
     *     <li>Specify if and how they should be cloned on 'get' (see <a href="#property_CLONE">Attribute.CLONE</a> for supported clone modes).</li>
 
176
     * </ul>
 
177
     *
 
178
     * <p>See the <a href="#method_addAtt">addAtt</a> method, for details about how to add attributes with
 
179
     * a specific configuration</p>
 
180
     *
 
181
     * @class Attribute
 
182
     * @uses Event.Target
 
183
     */
 
184
    function Attribute() {
 
185
        Y.Event.Target.call(this, {emitFacade:true});
 
186
        this._conf = this._conf || new Y.State();
 
187
        Y.log('att constructor called', 'info', 'attribute');
 
188
    }
 
189
 
 
190
    /**
 
191
     * <p>
 
192
     * Constants for clone formats supported by Attribute.
 
193
     * </p>
 
194
     * <p>
 
195
     * By default attribute values returned by the get method
 
196
     * are not cloned. However setting the attribute's "clone"
 
197
     * property to:
 
198
     * </p>
 
199
     * <dl>
 
200
     *     <dt>Attribute.CLONE.DEEP</dt>
 
201
     *     <dd>Will result in a deep cloned value being returned
 
202
     *        (using YUI's clone method). This can be expensive for complex
 
203
     *        objects.
 
204
     *     </dd>
 
205
     *     <dt>Attribute.CLONE.SHALLOW</dt>
 
206
     *     <dd>Will result in a shallow cloned value being returned
 
207
     *        (using YUI's merge method).
 
208
     *     </dd>
 
209
     *     <dt>Attribute.CLONE.IMMUTABLE</dt>
 
210
     *     <dd>Will result in a deep cloned value being returned
 
211
     *         when using the get method. Additionally users will
 
212
     *         not be able to set sub values of the attribute 
 
213
     *         using the complex attribute notation (obj.set("x.y.z, 5)).
 
214
     *         However the value of the attribute can be changed, making
 
215
     *         it different from a READONLY attribute.
 
216
     *     </dd>
 
217
     *     <dt>Attribute.CLONE.NONE</dt>
 
218
     *     <dd>
 
219
     *         The value will not be cloned, resulting in a reference
 
220
     *         to the stored value being passed back, if the value is an object.
 
221
     *         This is the default behavior.
 
222
     *     </dd>
 
223
     * </dl>
 
224
     * 
 
225
     * @property CLONE
 
226
     * @static
 
227
     * @final
 
228
     * @type Object
 
229
     */
 
230
    Attribute.CLONE = {
 
231
        NONE : 0,
 
232
        DEEP : 1,
 
233
        SHALLOW : 2,
 
234
        IMMUTABLE: 3
 
235
    };
 
236
 
 
237
    CLONE_ENUM = Attribute.CLONE;
 
238
 
 
239
    Attribute.prototype = {
 
240
        /**
 
241
         * <p>
 
242
         * Adds an attribute, with the provided configuration to the host object. Intended
 
243
         * to be used by the host object to setup it's set of available attributes.
 
244
         * </p>
 
245
         * <p>
 
246
         * The config argument object literal supports the following optional properties:
 
247
         * </p>
 
248
         * <dl>
 
249
         *    <dt>value &#60;Any&#62;</dt>
 
250
         *    <dd>The initial value to set on the attribute</dd>
 
251
         *    <dt>readOnly &#60;Boolean&#62;</dt>
 
252
         *    <dd>Whether or not the attribute is read only. Attributes having readOnly set to true
 
253
         *        cannot be set by invoking the set method.</dd>
 
254
         *    <dt>writeOnce &#60;Boolean&#62;</dt>
 
255
         *    <dd>Whether or not the attribute is "write once". Attributes having writeOnce set to true, 
 
256
         *        can only have their values set once, be it through the default configuration, 
 
257
         *        constructor configuration arguments, or by invoking set.</dd>
 
258
         *    <dt>set &#60;Function&#62;</dt>
 
259
         *    <dd>The setter function to be invoked (within the context of the host object) before 
 
260
         *        the attribute is stored by a call to the set method. The value returned by the 
 
261
         *        set function will be the finally stored value.</dd>
 
262
         *    <dt>get &#60;Function&#62;</dt>
 
263
         *    <dd>The getter function to be invoked (within the context of the host object) before
 
264
         *    the stored values is returned to a user invoking the get method for the attribute.
 
265
         *    The value returned by the get function is the final value which will be returned to the 
 
266
         *    user when they invoke get.</dd>
 
267
         *    <dt>validator &#60;Function&#62;</dt>
 
268
         *    <dd>The validator function which is invoked prior to setting the stored value. Returning
 
269
         *    false from the validator function will prevent the value from being stored</dd>
 
270
         *    <dt>clone &#60;int&#62;</dt>
 
271
         *    <dd>If and how the value returned by a call to the get method, should be de-referenced from
 
272
         *    the stored value. By default values are not cloned, and hence a call to get will return
 
273
         *    a reference to the stored value. See Attribute.CLONE for more details about the clone 
 
274
         *    options available</dd>
 
275
         * </dl>
 
276
         *
 
277
         * @method addAtt
 
278
         * 
 
279
         * @param {String} name The attribute key
 
280
         * @param {Object} config (optional) An object literal specifying the configuration for the attribute.
 
281
         * <strong>NOTE:</strong> The config object is modified when adding an attribute, 
 
282
         * so if you need to protect the original values, you will need to merge or clone the object.
 
283
         * 
 
284
         */
 
285
        addAtt: function(name, config) {
 
286
            Y.log('adding attribute: ' + name, 'info', 'attribute');
 
287
            var value, hasValue = (VALUE in config);
 
288
 
 
289
            if (config[READ_ONLY] && !hasValue) { Y.log('readOnly attribute: ' + name + ', added without an initial value. Value will be set on intial call to set', 'warn', 'attribute');}
 
290
 
 
291
            if(hasValue) {
 
292
                value = config.value;
 
293
                delete config.value;
 
294
            }
 
295
 
 
296
            this._conf.add(name, config);
 
297
 
 
298
            if (hasValue) {
 
299
                this.set(name, value);
 
300
            }
 
301
        },
 
302
 
 
303
        /**
 
304
         * Removes an attribute.
 
305
         *
 
306
         * @method removeAtt
 
307
         * @param {String} name The attribute key
 
308
         */
 
309
        removeAtt: function(name) {
 
310
            this._conf.remove(name);
 
311
        },
 
312
 
 
313
        /**
 
314
         * Returns the current value of the attribute. If the attribute
 
315
         * has been configured with a 'get' handler, this method will delegate
 
316
         * to the 'get' handler to obtain the value of the attribute.
 
317
         * The 'get' handler will be passed the current value of the attribute 
 
318
         * as the only argument.
 
319
         *
 
320
         * @method get
 
321
         *
 
322
         * @param {String} key The attribute whose value will be returned. If
 
323
         * the value of the attribute is an Object, dot notation can be used to
 
324
         * obtain the value of a property of the object (e.g. <code>get("x.y.z")</code>)
 
325
         * 
 
326
         * @return {Any} The current value of the attribute
 
327
         */
 
328
        get: function(name) {
 
329
 
 
330
            var conf = this._conf,
 
331
                path,
 
332
                getFn,
 
333
                clone,
 
334
                val;
 
335
 
 
336
            if (name.indexOf(DOT) !== -1) {
 
337
                path = name.split(DOT);
 
338
                name = path.shift();
 
339
            }
 
340
 
 
341
            val = conf.get(name, VALUE);
 
342
            getFn = conf.get(name, GET);
 
343
            clone = conf.get(name, CLONE);
 
344
 
 
345
            val = (clone) ? this._cloneAttVal(val, clone) : val;
 
346
            val = (getFn) ? getFn.call(this, val) : val;
 
347
            val = (path) ? this._getSubAttVal(path, val) : val;
 
348
 
 
349
            return val;
 
350
        },
 
351
 
 
352
        /**
 
353
         * Sets the value of an attribute.
 
354
         *
 
355
         * @method set
 
356
         * @chainable
 
357
         * 
 
358
         * @param {String} name The name of the attribute. Note, if the 
 
359
         * value of the attribute is an Object, dot notation can be used
 
360
         * to set the value of a property within the object 
 
361
         * (e.g. <code>set("x.y.z", 5)</code>), if the attribute has not
 
362
         * been declared as an immutable attribute (see <a href="#property_CLONE">Attribute.CLONE</a>).
 
363
         * 
 
364
         * @param {Any} value The value to apply to the attribute
 
365
         * 
 
366
         * @param {Object} opts Optional event data. This object will be mixed into
 
367
         * the event facade passed as the first argument to subscribers 
 
368
         * of attribute change events
 
369
         * 
 
370
         * @return {Object} Reference to the host object
 
371
         */
 
372
        set: function(name, val, opts) {
 
373
 
 
374
            var conf = this._conf,
 
375
                data = conf.data,
 
376
                strPath,
 
377
                path,
 
378
                currVal,
 
379
                initialSet = (!data.value || !(name in data.value));
 
380
 
 
381
            if (name.indexOf(DOT) !== -1) {
 
382
                strPath = name;
 
383
                path = name.split(DOT);
 
384
                name = path.shift();
 
385
            }
 
386
 
 
387
            if (path && conf.get(name, CLONE) === CLONE_ENUM.IMMUTABLE) {
 
388
                Y.log('set ' + name + ' failed; Attribute is IMMUTABLE. Setting a sub value is not permitted', 'info', 'attribute');
 
389
                return this;
 
390
            }
 
391
 
 
392
            if (!initialSet) {
 
393
                if (conf.get(name, WRITE_ONCE)) {
 
394
                    Y.log('set ' + name + ' failed; Attribute is writeOnce', 'info', 'attribute');
 
395
                    return this;
 
396
                }
 
397
                if (conf.get(name, READ_ONLY)) {
 
398
                    Y.log('set ' + name + ' failed; Attribute is readOnly', 'info', 'attribute');
 
399
                    return this;
 
400
                }
 
401
            }
 
402
 
 
403
            if (!conf.get(name)) {
 
404
                Y.log('Set called with unconfigured attribute. Adding a new attribute: ' + name, 'info', 'attribute');
 
405
            }
 
406
 
 
407
            currVal = this.get(name);
 
408
 
 
409
            if (path) {
 
410
               val = this._setSubAttVal(path, Y.clone(currVal), val);
 
411
               if (val === undefined) {
 
412
                   // Path not valid, don't set anything.
 
413
                   Y.log('set ' + strPath + 'failed; attribute sub path is invalid', 'error', 'attribute');
 
414
                   return this;
 
415
               }
 
416
            }
 
417
 
 
418
            this._fireAttChange(name, currVal, val, name, strPath, opts);
 
419
 
 
420
            return this;
 
421
        },
 
422
 
 
423
        /**
 
424
         * <p>
 
425
         * Alias for the Event.Target <a href="Event.Target.html#method_subscribe">subscribe</a> method.
 
426
         * </p>
 
427
         * 
 
428
         * <p>Subscribers using this method to listen for attribute change events will be notified just
 
429
         * <strong>before</strong> the state of the attribute has been modified, and before the default handler has been
 
430
         * invoked.</p>
 
431
         * 
 
432
         * <p>The <a href="Event.Target.html#method_after">after</a> method, inherited from Event Target, can be used by subscribers
 
433
         * who wish to be notified <strong>after</strong> the attribute's value has changed.</p>
 
434
         * 
 
435
         * @param {String} type The event type. For attribute change events, the event type is "[Attribute Name]Change", e.g.
 
436
         * for the attribute "enabled", the event type will be "enabledChange".
 
437
         * @param {Function} fn The subscribed function to invoke
 
438
         * @param {Object} context Optional execution context
 
439
         * @param {Any*} args* 0..n additional arguments to append to supply to the subscribed function when the event fires.
 
440
         * @method on
 
441
         * @return {Event.Handle} The handle object for unsubscribing the subscriber from the event.
 
442
         */
 
443
        on : function() {
 
444
            return this.subscribe.apply(this, arguments);
 
445
        },
 
446
 
 
447
        /**
 
448
         * Default handler implementation for set events
 
449
         *
 
450
         * @private
 
451
         * @method _defAttSet
 
452
         * @param {Event.Facade} e The event object for the custom event
 
453
         */
 
454
        _defAttSet : function(e) {
 
455
            var conf = this._conf,
 
456
                name = e.attrName,
 
457
                val = e.newVal,
 
458
                retVal,
 
459
                valFn  = conf.get(name, VALIDATOR),
 
460
                setFn = conf.get(name, SET);
 
461
 
 
462
            if (setFn) {
 
463
                retVal = setFn.call(this, val);
 
464
                if (retVal !== undefined) {
 
465
                    Y.log('attribute: ' + name + ' modified by setter', 'info', 'attribute');
 
466
                    val = retVal; // setter can change value
 
467
                }
 
468
            }
 
469
 
 
470
            if (!valFn || valFn.call(this, val)) {
 
471
                conf.add(name, { value: val });
 
472
                e.newVal = conf.get(name, VALUE);
 
473
            } else {
 
474
                // Prevent "after" listeners from being 
 
475
                // invoked since nothing changed.
 
476
                e.stopImmediatePropagation();
 
477
            }
 
478
        },
 
479
 
 
480
        /**
 
481
         * Retrieves the sub value at the provided path,
 
482
         * from the value object provided.
 
483
         *
 
484
         * @method _getSubAttVal
 
485
         * @private
 
486
         *
 
487
         * @param {Array} path  A path array, specifying the object traversal path
 
488
         *                      from which to obtain the sub value.
 
489
         * @param {Object} val  The object from which to extract the property value
 
490
         * @return {Any} The value stored in the path or undefined if not found.
 
491
         */
 
492
        _getSubAttVal: function (path, val) {
 
493
            var pl = path.length,
 
494
                i;
 
495
 
 
496
            if (pl > 0) {
 
497
                for (i = 0; val !== undefined && i < pl; ++i) {
 
498
                    val = val[path[i]];
 
499
                }
 
500
            }
 
501
 
 
502
            return val;
 
503
        },
 
504
 
 
505
        /**
 
506
         * Sets the sub value at the provided path on the value object.
 
507
         * Returns the modified value object, or undefined if the path is invalid.
 
508
         *
 
509
         * @method _setSubAttVal
 
510
         * @private
 
511
         * 
 
512
         * @param {Array} path  A path array, specifying the object traversal path
 
513
         *                      at which to set the sub value.
 
514
         * @param {Object} val  The object on which to set the sub value.
 
515
         * @param {Any} subval  The sub value to set.
 
516
         * @return {Object}     The modified object, with the new sub value set, or 
 
517
         *                      undefined, if the path was invalid.
 
518
         */
 
519
        _setSubAttVal: function(path, val, subval) {
 
520
 
 
521
            var leafIdx = path.length-1,
 
522
                i,
 
523
                o;
 
524
 
 
525
            if (leafIdx >= 0) {
 
526
                o = val;
 
527
 
 
528
                for (i = 0; o !== undefined && i < leafIdx; ++i) {
 
529
                    o = o[path[i]];
 
530
                }
 
531
 
 
532
                // Not preventing new properties from being added
 
533
                if (o !== undefined /* && o[path[i]] !== undefined */) {
 
534
                    o[path[i]] = subval;
 
535
                } else {
 
536
                    val = undefined;
 
537
                }
 
538
            }
 
539
 
 
540
            return val;
 
541
        },
 
542
 
 
543
        /**
 
544
         * Sets multiple attribute values.
 
545
         * 
 
546
         * @method setAtts
 
547
         * @param {Object} atts  A hash of attributes: name/value pairs
 
548
         */
 
549
        setAtts: function(atts) {
 
550
            for (var att in atts) {
 
551
                if ( O.owns(atts, att) ) {
 
552
                    this.set(att, atts[att]);
 
553
                }
 
554
            }
 
555
        },
 
556
 
 
557
        /**
 
558
         * Gets multiple attribute values.
 
559
         *
 
560
         * @method getAtts
 
561
         * @return {Object} A hash of attributes: name/value pairs
 
562
         */
 
563
        getAtts: function(atts) {
 
564
            var o = {};
 
565
            if (atts) {
 
566
                o = Y.clone(atts);
 
567
            } else {
 
568
                Y.each(this._conf.get(VALUE), function(val, att) {
 
569
                    o[att] = val; 
 
570
                });
 
571
            }
 
572
            return o;
 
573
        },
 
574
 
 
575
        /**
 
576
         * Configures attributes, and sets initial values
 
577
         *
 
578
         * @method _initAtts
 
579
         * @protected
 
580
         * 
 
581
         * @param {Object} cfg Attribute configuration object literal
 
582
         * @param {Object} initValues Name/value hash of initial values to apply
 
583
         */
 
584
        _initAtts : function(cfg, initValues) {
 
585
            if (cfg) {
 
586
                var att,
 
587
                    attCfg,
 
588
                    values,
 
589
                    value,
 
590
                    atts = cfg;
 
591
 
 
592
                values = this._splitAttVals(initValues);
 
593
 
 
594
                for (att in atts) {
 
595
                    if (O.owns(atts, att)) {
 
596
                        attCfg = Y.merge(atts[att]);
 
597
                        value = this._initAttVal(att, attCfg, values);
 
598
                        if (value !== undefined) {
 
599
                            attCfg.value = value;
 
600
                        }
 
601
                        this.addAtt(att, attCfg);
 
602
                    }
 
603
                }
 
604
            }
 
605
        },
 
606
 
 
607
        /**
 
608
         * Utility to split out regular attribute values
 
609
         * from complex attribute values, so that complex
 
610
         * attributes can be keyed by top level attribute name.
 
611
         *
 
612
         * @method _splitAttrValues
 
613
         * @param {Object} valueHash Name/value hash of initial values
 
614
         *
 
615
         * @return {Object} Object literal with 2 properties - "simple" and "complex",
 
616
         * containing simple and complex attribute values respectively keyed 
 
617
         * by attribute the top level attribute name.
 
618
         * @private
 
619
         */
 
620
        _splitAttVals: function(valueHash) {
 
621
            var vals = {},
 
622
                subvals = {},
 
623
                path,
 
624
                attr,
 
625
                v;
 
626
 
 
627
            for (var k in valueHash) {
 
628
                if (O.owns(valueHash, k)) {
 
629
                    if (k.indexOf(DOT) !== -1) {
 
630
                        path = k.split(DOT);
 
631
                        attr = path.shift();
 
632
                        v = subvals[attr] = subvals[attr] || [];
 
633
                        v[v.length] = {
 
634
                            path : path, 
 
635
                            value: valueHash[k]
 
636
                        };
 
637
                    } else {
 
638
                        vals[k] = valueHash[k];
 
639
                    }
 
640
                }
 
641
            }
 
642
            return { simple:vals, complex:subvals };
 
643
        },
 
644
 
 
645
        /**
 
646
         * Returns the initial value of the given attribute from
 
647
         * either the default configuration provided, or the 
 
648
         * over-ridden value if it exists in the initValues 
 
649
         * hash provided.
 
650
         *
 
651
         * @param {String} att Attribute name
 
652
         * @param {Object} cfg Default attribute configuration
 
653
         * object literal
 
654
         * @param {Object} initVales Initial attribute values, provided 
 
655
         * for the instance
 
656
         *
 
657
         * @return {Any} Initial value of the attribute.
 
658
         *
 
659
         * @method _initAttVal
 
660
         * @private
 
661
         */
 
662
        _initAttVal : function(att, cfg, initValues) {
 
663
 
 
664
            var hasVal = (VALUE in cfg),
 
665
                val = cfg.value,
 
666
                simple,
 
667
                complex,
 
668
                i,
 
669
                l,
 
670
                path,
 
671
                subval,
 
672
                subvals;
 
673
 
 
674
            if (!cfg[READ_ONLY] && initValues) {
 
675
                // Simple Attributes
 
676
                simple = initValues.simple;
 
677
                if (simple && O.owns(simple, att)) {
 
678
                    hasVal = true;
 
679
                    val = simple[att];
 
680
                }
 
681
 
 
682
                // Complex Attributes
 
683
                complex = initValues.complex;
 
684
                if (complex && O.owns(complex, att)) {
 
685
                    hasVal = true;
 
686
                    subvals = complex[att];
 
687
                    for (i = 0, l = subvals.length; i < l; ++i) {
 
688
                        path = subvals[i].path;
 
689
                        subval = subvals[i].value;
 
690
                        val = this._setSubAttVal(path, val, subval);
 
691
                    }
 
692
                }
 
693
            }
 
694
 
 
695
            return val;
 
696
        },
 
697
 
 
698
        /**
 
699
         * <p>
 
700
         * Clone utility method, which will 
 
701
         * clone the provided value using YUI's 
 
702
         * merge, or clone utilities based
 
703
         * on the clone type provided. See <a href="#property_CLONE">Attribute.CLONE</a>
 
704
         * </p>
 
705
         * 
 
706
         * @method _cloneAttVal
 
707
         * @private 
 
708
         * @param {Any} val Value to clone
 
709
         * @param {int} type Clone type to use, See the CLONE property
 
710
         * @return {Any} The cloned copy of the object, based on the provided type.
 
711
         */
 
712
        _cloneAttVal : function(val, type) {
 
713
            switch(type) {
 
714
                case CLONE_ENUM.SHALLOW:
 
715
                    val = Y.merge(val);
 
716
                    break;
 
717
                case CLONE_ENUM.DEEP:
 
718
                case CLONE_ENUM.IMMUTABLE:
 
719
                    val = Y.clone(val);
 
720
                    break;
 
721
            }
 
722
            return val;
 
723
        },
 
724
 
 
725
        /**
 
726
         * Utility method to help setup the event payload and 
 
727
         * fire the attribute change event.
 
728
         * 
 
729
         * @method _fireAttChange
 
730
         * @private
 
731
         * @param {String} type The event name
 
732
         * @param {Any} currVal The current value of the attribute
 
733
         * @param {Any} newVal The new value of the attribute
 
734
         * @param {String} attrName The name of the attribute
 
735
         * @param {String} strFullPath The full path of the property being changed, 
 
736
         * if this is a sub-attribute value being change
 
737
         * @param {Function} defaultFn The default handler for the change event
 
738
         * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
 
739
         */
 
740
        _fireAttChange: function(type, currVal, newVal, attrName, strFullPath, defaultFn, opts) {
 
741
            type = type + CHANGE;
 
742
 
 
743
            // TODO: Publishing temporarily, while we address event bubbling/queuing
 
744
            this.publish(type, {queuable:false, defaultFn:this._defAttSet});
 
745
 
 
746
            var eData = {
 
747
                type: type,
 
748
                prevVal: currVal,
 
749
                newVal: newVal,
 
750
                attrName: attrName,
 
751
                subAttrName: strFullPath
 
752
            };
 
753
 
 
754
            if (opts) {
 
755
                Y.mix(eData, opts);
 
756
            }
 
757
 
 
758
            this.fire(eData);
 
759
        }
 
760
    };
 
761
 
 
762
    Y.mix(Attribute, Y.Event.Target, false, null, 1);
 
763
 
 
764
    Y.Attribute = Attribute;
 
765
 
 
766
 
 
767
 
 
768
}, '3.0.0pr1' ,{requires:['event']});