/loggerhead/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/loggerhead/trunk

« back to all changes in this revision

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

  • Committer: Colin Watson
  • Date: 2020-06-08 09:55:03 UTC
  • mfrom: (498.2.2 jquery)
  • Revision ID: cjwatson@canonical.com-20200608095503-n387xggxud2khqsw
[r=cjwatson] Port loggerhead from YUI to jQuery.

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.0pr2
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
 
                o;
94
 
 
95
 
            if (key) {
96
 
                return (d[key] && name in d[key]) ?  d[key][name] : undefined;
97
 
            } else {
98
 
                Y.each(d, function(v, k) {
99
 
                    if (name in d[k]) {
100
 
                        o = o || {};
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
 
            config.initValue = value;
297
 
            this._conf.add(name, config);
298
 
 
299
 
            if (hasValue) {
300
 
                this.set(name, value);
301
 
            }
302
 
        },
303
 
 
304
 
        /**
305
 
         * Resets the given attribute or all attributes to the initial value.
306
 
         *
307
 
         * @method reset
308
 
         * @param {String} name optional An attribute to reset.  If omitted, all attributes are reset
309
 
         */
310
 
        reset: function(name) {
311
 
            if (name) {
312
 
                this.set(name, this._conf.data['initValue'][name]);
313
 
            } else {
314
 
                var initVals = this._conf.data['initValue'];
315
 
                Y.each(initVals, function(v, n) {
316
 
                    this._set(n, v);
317
 
                }, this);
318
 
            }
319
 
        },
320
 
 
321
 
        /**
322
 
         * Removes an attribute.
323
 
         *
324
 
         * @method removeAtt
325
 
         * @param {String} name The attribute key
326
 
         */
327
 
        removeAtt: function(name) {
328
 
            this._conf.remove(name);
329
 
        },
330
 
 
331
 
        /**
332
 
         * Returns the current value of the attribute. If the attribute
333
 
         * has been configured with a 'get' handler, this method will delegate
334
 
         * to the 'get' handler to obtain the value of the attribute.
335
 
         * The 'get' handler will be passed the current value of the attribute 
336
 
         * as the only argument.
337
 
         *
338
 
         * @method get
339
 
         *
340
 
         * @param {String} key The attribute whose value will be returned. If
341
 
         * the value of the attribute is an Object, dot notation can be used to
342
 
         * obtain the value of a property of the object (e.g. <code>get("x.y.z")</code>)
343
 
         * 
344
 
         * @return {Any} The current value of the attribute
345
 
         */
346
 
        get: function(name) {
347
 
 
348
 
            var conf = this._conf,
349
 
                path,
350
 
                getFn,
351
 
                clone,
352
 
                val;
353
 
 
354
 
            if (name.indexOf(DOT) !== -1) {
355
 
                path = name.split(DOT);
356
 
                name = path.shift();
357
 
            }
358
 
 
359
 
            val = conf.get(name, VALUE);
360
 
            getFn = conf.get(name, GET);
361
 
            clone = conf.get(name, CLONE);
362
 
 
363
 
            val = (clone) ? this._cloneAttVal(val, clone) : val;
364
 
            val = (getFn) ? getFn.call(this, val) : val;
365
 
            val = (path) ? this._getSubAttVal(path, val) : val;
366
 
 
367
 
            return val;
368
 
        },
369
 
 
370
 
        /**
371
 
         * Allows setting of readOnly/writeOnce attributes.
372
 
         *
373
 
         * @method _set
374
 
         * @protected
375
 
         * @chainable
376
 
         * @return {Object} Reference to the host object
377
 
         */
378
 
        _set: function(name, val, opts) {
379
 
            return this.set(name, val, opts, true);
380
 
        },
381
 
 
382
 
        /**
383
 
         * Sets the value of an attribute.
384
 
         *
385
 
         * @method set
386
 
         * @chainable
387
 
         * 
388
 
         * @param {String} name The name of the attribute. Note, if the 
389
 
         * value of the attribute is an Object, dot notation can be used
390
 
         * to set the value of a property within the object 
391
 
         * (e.g. <code>set("x.y.z", 5)</code>), if the attribute has not
392
 
         * been declared as an immutable attribute (see <a href="#property_CLONE">Attribute.CLONE</a>).
393
 
         * 
394
 
         * @param {Any} value The value to apply to the attribute
395
 
         * 
396
 
         * @param {Object} opts Optional event data. This object will be mixed into
397
 
         * the event facade passed as the first argument to subscribers 
398
 
         * of attribute change events
399
 
         * 
400
 
         * @return {Object} Reference to the host object
401
 
         */
402
 
        set: function(name, val, opts, privateSet) {
403
 
            var conf = this._conf,
404
 
                data = conf.data,
405
 
                strPath,
406
 
                path,
407
 
                currVal,
408
 
                initialSet = (!data.value || !(name in data.value));
409
 
 
410
 
            if (name.indexOf(DOT) !== -1) {
411
 
                strPath = name;
412
 
                path = name.split(DOT);
413
 
                name = path.shift();
414
 
            }
415
 
 
416
 
            if (path && conf.get(name, CLONE) === CLONE_ENUM.IMMUTABLE) {
417
 
                Y.log('set ' + name + ' failed; Attribute is IMMUTABLE. Setting a sub value is not permitted', 'info', 'attribute');
418
 
                return this;
419
 
            }
420
 
 
421
 
            if (!initialSet && !privateSet) {
422
 
                if (conf.get(name, WRITE_ONCE)) {
423
 
                    Y.log('set ' + name + ' failed; Attribute is writeOnce', 'info', 'attribute');
424
 
                    return this;
425
 
                }
426
 
                if (conf.get(name, READ_ONLY)) {
427
 
                    Y.log('set ' + name + ' failed; Attribute is readOnly', 'info', 'attribute');
428
 
                    return this;
429
 
                }
430
 
            }
431
 
 
432
 
            if (!conf.get(name)) {
433
 
                //Y.log('Set called with unconfigured attribute. Adding a new attribute: ' + name, 'info', 'attribute');
434
 
                Y.log('set ' + name + ' failed; Attribute is not configured', 'info', 'attribute');
435
 
                return this;
436
 
            }
437
 
 
438
 
            currVal = this.get(name);
439
 
 
440
 
            if (path) {
441
 
               val = this._setSubAttVal(path, Y.clone(currVal), val);
442
 
               if (val === undefined) {
443
 
                   // Path not valid, don't set anything.
444
 
                   Y.log('set ' + strPath + 'failed; attribute sub path is invalid', 'error', 'attribute');
445
 
                   return this;
446
 
               }
447
 
            }
448
 
 
449
 
            this._fireAttChange(name, currVal, val, name, strPath, opts);
450
 
 
451
 
            return this;
452
 
        },
453
 
 
454
 
        /**
455
 
         * <p>
456
 
         * Alias for the Event.Target <a href="Event.Target.html#method_subscribe">subscribe</a> method.
457
 
         * </p>
458
 
         * 
459
 
         * <p>Subscribers using this method to listen for attribute change events will be notified just
460
 
         * <strong>before</strong> the state of the attribute has been modified, and before the default handler has been
461
 
         * invoked.</p>
462
 
         * 
463
 
         * <p>The <a href="Event.Target.html#method_after">after</a> method, inherited from Event Target, can be used by subscribers
464
 
         * who wish to be notified <strong>after</strong> the attribute's value has changed.</p>
465
 
         * 
466
 
         * @param {String} type The event type. For attribute change events, the event type is "[Attribute Name]Change", e.g.
467
 
         * for the attribute "enabled", the event type will be "enabledChange".
468
 
         * @param {Function} fn The subscribed function to invoke
469
 
         * @param {Object} context Optional execution context
470
 
         * @param {Any*} args* 0..n additional arguments to append to supply to the subscribed function when the event fires.
471
 
         * @method on
472
 
         * @return {Event.Handle} The handle object for unsubscribing the subscriber from the event.
473
 
         */
474
 
        on : function() {
475
 
            return this.subscribe.apply(this, arguments);
476
 
        },
477
 
 
478
 
        /**
479
 
         * Default handler implementation for set events
480
 
         *
481
 
         * @private
482
 
         * @method _defAttSet
483
 
         * @param {Event.Facade} e The event object for the custom event
484
 
         */
485
 
        _defAttSet : function(e) {
486
 
            var conf = this._conf,
487
 
                name = e.attrName,
488
 
                val = e.newVal,
489
 
                retVal,
490
 
                valFn  = conf.get(name, VALIDATOR),
491
 
                setFn = conf.get(name, SET);
492
 
 
493
 
            if (setFn) {
494
 
                retVal = setFn.call(this, val);
495
 
                if (retVal !== undefined) {
496
 
                    Y.log('attribute: ' + name + ' modified by setter', 'info', 'attribute');
497
 
                    val = retVal; // setter can change value
498
 
                }
499
 
            }
500
 
 
501
 
            if (!valFn || valFn.call(this, val)) {
502
 
                conf.add(name, { value: val });
503
 
                e.newVal = conf.get(name, VALUE);
504
 
            } else {
505
 
                // Prevent "after" listeners from being 
506
 
                // invoked since nothing changed.
507
 
                e.stopImmediatePropagation();
508
 
            }
509
 
        },
510
 
 
511
 
        /**
512
 
         * Retrieves the sub value at the provided path,
513
 
         * from the value object provided.
514
 
         *
515
 
         * @method _getSubAttVal
516
 
         * @private
517
 
         *
518
 
         * @param {Array} path  A path array, specifying the object traversal path
519
 
         *                      from which to obtain the sub value.
520
 
         * @param {Object} val  The object from which to extract the property value
521
 
         * @return {Any} The value stored in the path or undefined if not found.
522
 
         */
523
 
        _getSubAttVal: function (path, val) {
524
 
            var pl = path.length,
525
 
                i;
526
 
 
527
 
            if (pl > 0) {
528
 
                for (i = 0; val !== undefined && i < pl; ++i) {
529
 
                    val = val[path[i]];
530
 
                }
531
 
            }
532
 
 
533
 
            return val;
534
 
        },
535
 
 
536
 
        /**
537
 
         * Sets the sub value at the provided path on the value object.
538
 
         * Returns the modified value object, or undefined if the path is invalid.
539
 
         *
540
 
         * @method _setSubAttVal
541
 
         * @private
542
 
         * 
543
 
         * @param {Array} path  A path array, specifying the object traversal path
544
 
         *                      at which to set the sub value.
545
 
         * @param {Object} val  The object on which to set the sub value.
546
 
         * @param {Any} subval  The sub value to set.
547
 
         * @return {Object}     The modified object, with the new sub value set, or 
548
 
         *                      undefined, if the path was invalid.
549
 
         */
550
 
        _setSubAttVal: function(path, val, subval) {
551
 
 
552
 
            var leafIdx = path.length-1,
553
 
                i,
554
 
                o;
555
 
 
556
 
            if (leafIdx >= 0) {
557
 
                o = val;
558
 
 
559
 
                for (i = 0; o !== undefined && i < leafIdx; ++i) {
560
 
                    o = o[path[i]];
561
 
                }
562
 
 
563
 
                // Not preventing new properties from being added
564
 
                if (o !== undefined /* && o[path[i]] !== undefined */) {
565
 
                    o[path[i]] = subval;
566
 
                } else {
567
 
                    val = undefined;
568
 
                }
569
 
            }
570
 
 
571
 
            return val;
572
 
        },
573
 
 
574
 
        /**
575
 
         * Sets multiple attribute values.
576
 
         * 
577
 
         * @method setAtts
578
 
         * @param {Object} atts  A hash of attributes: name/value pairs
579
 
         */
580
 
        setAtts: function(atts) {
581
 
            for (var att in atts) {
582
 
                if ( O.owns(atts, att) ) {
583
 
                    this.set(att, atts[att]);
584
 
                }
585
 
            }
586
 
        },
587
 
 
588
 
        /**
589
 
         * Gets multiple attribute values.
590
 
         *
591
 
         * @method getAtts
592
 
         * @param {Array} Optional. An array of attribute names, whose values are required. If omitted, all attribute values are
593
 
         * returned.
594
 
         * @return {Object} A hash of attributes: name/value pairs
595
 
         */
596
 
        getAtts: function(atts) {
597
 
            var o = {}, i, l, att;
598
 
            atts = atts || O.keys(this._conf.data[VALUE]);
599
 
 
600
 
            for (i = 0, l = atts.length; i < l; i++) {
601
 
                // Go through get, to retrieve massaged values and honor cloning
602
 
                att = atts[i];
603
 
                o[att] = this.get(att); 
604
 
            }
605
 
 
606
 
            return o;
607
 
        },
608
 
 
609
 
        /**
610
 
         * Configures attributes, and sets initial values
611
 
         *
612
 
         * @method _initAtts
613
 
         * @protected
614
 
         * 
615
 
         * @param {Object} cfg Attribute configuration object literal
616
 
         * @param {Object} initValues Name/value hash of initial values to apply
617
 
         */
618
 
        _initAtts : function(cfg, initValues) {
619
 
            if (cfg) {
620
 
                var att,
621
 
                    attCfg,
622
 
                    values,
623
 
                    value,
624
 
                    atts = cfg;
625
 
 
626
 
                values = this._splitAttVals(initValues);
627
 
 
628
 
                for (att in atts) {
629
 
                    if (O.owns(atts, att)) {
630
 
                        attCfg = Y.merge(atts[att]);
631
 
                        value = this._initAttVal(att, attCfg, values);
632
 
                        if (value !== undefined) {
633
 
                            attCfg.value = value;
634
 
                        }
635
 
 
636
 
                        this.addAtt(att, attCfg);
637
 
                    }
638
 
                }
639
 
            }
640
 
        },
641
 
 
642
 
        /**
643
 
         * Utility to split out regular attribute values
644
 
         * from complex attribute values, so that complex
645
 
         * attributes can be keyed by top level attribute name.
646
 
         *
647
 
         * @method _splitAttrValues
648
 
         * @param {Object} valueHash Name/value hash of initial values
649
 
         *
650
 
         * @return {Object} Object literal with 2 properties - "simple" and "complex",
651
 
         * containing simple and complex attribute values respectively keyed 
652
 
         * by attribute the top level attribute name.
653
 
         * @private
654
 
         */
655
 
        _splitAttVals: function(valueHash) {
656
 
            var vals = {},
657
 
                subvals = {},
658
 
                path,
659
 
                attr,
660
 
                v;
661
 
 
662
 
            for (var k in valueHash) {
663
 
                if (O.owns(valueHash, k)) {
664
 
                    if (k.indexOf(DOT) !== -1) {
665
 
                        path = k.split(DOT);
666
 
                        attr = path.shift();
667
 
                        v = subvals[attr] = subvals[attr] || [];
668
 
                        v[v.length] = {
669
 
                            path : path, 
670
 
                            value: valueHash[k]
671
 
                        };
672
 
                    } else {
673
 
                        vals[k] = valueHash[k];
674
 
                    }
675
 
                }
676
 
            }
677
 
            return { simple:vals, complex:subvals };
678
 
        },
679
 
 
680
 
        /**
681
 
         * Returns the initial value of the given attribute from
682
 
         * either the default configuration provided, or the 
683
 
         * over-ridden value if it exists in the initValues 
684
 
         * hash provided.
685
 
         *
686
 
         * @param {String} att Attribute name
687
 
         * @param {Object} cfg Default attribute configuration
688
 
         * object literal
689
 
         * @param {Object} initVales Initial attribute values, provided 
690
 
         * for the instance
691
 
         *
692
 
         * @return {Any} Initial value of the attribute.
693
 
         *
694
 
         * @method _initAttVal
695
 
         * @private
696
 
         */
697
 
        _initAttVal : function(att, cfg, initValues) {
698
 
 
699
 
            var hasVal = (VALUE in cfg),
700
 
                val = (cfg.valueFn) ? cfg.valueFn.call(this) : cfg.value,
701
 
                simple,
702
 
                complex,
703
 
                i,
704
 
                l,
705
 
                path,
706
 
                subval,
707
 
                subvals;
708
 
 
709
 
            if (!cfg[READ_ONLY] && initValues) {
710
 
                // Simple Attributes
711
 
                simple = initValues.simple;
712
 
                if (simple && O.owns(simple, att)) {
713
 
                    hasVal = true;
714
 
                    val = simple[att];
715
 
                }
716
 
 
717
 
                // Complex Attributes
718
 
                complex = initValues.complex;
719
 
                if (complex && O.owns(complex, att)) {
720
 
                    hasVal = true;
721
 
                    subvals = complex[att];
722
 
                    for (i = 0, l = subvals.length; i < l; ++i) {
723
 
                        path = subvals[i].path;
724
 
                        subval = subvals[i].value;
725
 
                        val = this._setSubAttVal(path, val, subval);
726
 
                    }
727
 
                }
728
 
            }
729
 
 
730
 
            return val;
731
 
        },
732
 
 
733
 
        /**
734
 
         * <p>
735
 
         * Clone utility method, which will 
736
 
         * clone the provided value using YUI's 
737
 
         * merge, or clone utilities based
738
 
         * on the clone type provided. See <a href="#property_CLONE">Attribute.CLONE</a>
739
 
         * </p>
740
 
         * 
741
 
         * @method _cloneAttVal
742
 
         * @private 
743
 
         * @param {Any} val Value to clone
744
 
         * @param {int} type Clone type to use, See the CLONE property
745
 
         * @return {Any} The cloned copy of the object, based on the provided type.
746
 
         */
747
 
        _cloneAttVal : function(val, type) {
748
 
            switch(type) {
749
 
                case CLONE_ENUM.SHALLOW:
750
 
                    val = Y.merge(val);
751
 
                    break;
752
 
                case CLONE_ENUM.DEEP:
753
 
                case CLONE_ENUM.IMMUTABLE:
754
 
                    val = Y.clone(val);
755
 
                    break;
756
 
            }
757
 
            return val;
758
 
        },
759
 
 
760
 
        /**
761
 
         * Utility method to help setup the event payload and 
762
 
         * fire the attribute change event.
763
 
         * 
764
 
         * @method _fireAttChange
765
 
         * @private
766
 
         * @param {String} type The event name
767
 
         * @param {Any} currVal The current value of the attribute
768
 
         * @param {Any} newVal The new value of the attribute
769
 
         * @param {String} attrName The name of the attribute
770
 
         * @param {String} strFullPath The full path of the property being changed, 
771
 
         * if this is a sub-attribute value being change
772
 
         * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
773
 
         */
774
 
        _fireAttChange: function(type, currVal, newVal, attrName, strFullPath, opts) {
775
 
            type = type + CHANGE;
776
 
 
777
 
            // TODO: Publishing temporarily, while we address event bubbling/queuing
778
 
            this.publish(type, {queuable:false, defaultFn:this._defAttSet, silent:true});
779
 
 
780
 
            var eData = {
781
 
                type: type,
782
 
                prevVal: currVal,
783
 
                newVal: newVal,
784
 
                attrName: attrName,
785
 
                subAttrName: strFullPath
786
 
            };
787
 
 
788
 
            if (opts) {
789
 
                Y.mix(eData, opts);
790
 
            }
791
 
 
792
 
            this.fire(eData);
793
 
        }
794
 
    };
795
 
 
796
 
    Y.mix(Attribute, Y.Event.Target, false, null, 1);
797
 
 
798
 
    Y.Attribute = Attribute;
799
 
 
800
 
 
801
 
 
802
 
}, '3.0.0pr2' ,{requires:['event']});