~andreserl/maas/precise_packaging_sru

« back to all changes in this revision

Viewing changes to debian/extras/jslibs/yui/widget-base/widget-base-debug.js

  • Committer: Andres Rodriguez
  • Date: 2013-03-08 23:21:23 UTC
  • mfrom: (145.2.21 precise.sru)
  • Revision ID: andreserl@ubuntu.com-20130308232123-tws9nffx8f6eoa0f
* debian/maas-dhcp.maas-dhcp-server.upstart: leases file should be owned
  by user/group 'dhcpd' instead of root.
* debian/control: Force dependency version for python-django to
  (>= 1.3.1-4ubuntu1.7).
* Continue to ship yui3 and raphael with MAAS.
  - debian/patches/04_precise_no_yui_root.patch: Add.
  - debian/control: Drop dependencies on yui3 and raphael.
  - debian/source/include-binaries: Add to not FTBFS
  - debian/extras/jslibs: Ship JS libraries.
  - debian/copyright: Update copyright to reflect libraries license.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
YUI 3.5.1 (build 22)
 
3
Copyright 2012 Yahoo! Inc. All rights reserved.
 
4
Licensed under the BSD License.
 
5
http://yuilibrary.com/license/
 
6
*/
 
7
YUI.add('widget-base', function(Y) {
 
8
 
 
9
/**
 
10
 * Provides the base Widget class, with HTML Parser support
 
11
 *
 
12
 * @module widget
 
13
 * @main widget
 
14
 */
 
15
 
 
16
/**
 
17
 * Provides the base Widget class
 
18
 *
 
19
 * @module widget
 
20
 * @submodule widget-base
 
21
 */
 
22
var L = Y.Lang,
 
23
    Node = Y.Node,
 
24
 
 
25
    ClassNameManager = Y.ClassNameManager,
 
26
 
 
27
    _getClassName = ClassNameManager.getClassName,
 
28
    _getWidgetClassName,
 
29
 
 
30
    _toInitialCap = Y.cached(function(str) {
 
31
        return str.substring(0, 1).toUpperCase() + str.substring(1);
 
32
    }),
 
33
 
 
34
    // K-Weight, IE GC optimizations
 
35
    CONTENT = "content",
 
36
    VISIBLE = "visible",
 
37
    HIDDEN = "hidden",
 
38
    DISABLED = "disabled",
 
39
    FOCUSED = "focused",
 
40
    WIDTH = "width",
 
41
    HEIGHT = "height",
 
42
    BOUNDING_BOX = "boundingBox",
 
43
    CONTENT_BOX = "contentBox",
 
44
    PARENT_NODE = "parentNode",
 
45
    OWNER_DOCUMENT = "ownerDocument",
 
46
    AUTO = "auto",
 
47
    SRC_NODE = "srcNode",
 
48
    BODY = "body",
 
49
    TAB_INDEX = "tabIndex",
 
50
    ID = "id",
 
51
    RENDER = "render",
 
52
    RENDERED = "rendered",
 
53
    DESTROYED = "destroyed",
 
54
    STRINGS = "strings",
 
55
    DIV = "<div></div>",
 
56
    CHANGE = "Change",
 
57
    LOADING = "loading",
 
58
 
 
59
    _UISET = "_uiSet",
 
60
 
 
61
    EMPTY_STR = "",
 
62
    EMPTY_FN = function() {},
 
63
 
 
64
    TRUE = true,
 
65
    FALSE = false,
 
66
 
 
67
    UI,
 
68
    ATTRS = {},
 
69
    UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX],
 
70
 
 
71
    WEBKIT = Y.UA.webkit,
 
72
 
 
73
    // Widget nodeid-to-instance map.
 
74
    _instances = {};
 
75
 
 
76
/**
 
77
 * A base class for widgets, providing:
 
78
 * <ul>
 
79
 *    <li>The render lifecycle method, in addition to the init and destroy 
 
80
 *        lifecycle methods provide by Base</li>
 
81
 *    <li>Abstract methods to support consistent MVC structure across 
 
82
 *        widgets: renderer, renderUI, bindUI, syncUI</li>
 
83
 *    <li>Support for common widget attributes, such as boundingBox, contentBox, visible, 
 
84
 *        disabled, focused, strings</li>
 
85
 * </ul>
 
86
 *
 
87
 * @param config {Object} Object literal specifying widget configuration properties.
 
88
 *
 
89
 * @class Widget
 
90
 * @constructor
 
91
 * @extends Base
 
92
 */
 
93
function Widget(config) {
 
94
    Y.log('constructor called', 'life', 'widget');
 
95
 
 
96
    // kweight
 
97
    var widget = this,
 
98
        parentNode,
 
99
        render, 
 
100
        constructor = widget.constructor; 
 
101
 
 
102
    widget._strs = {};
 
103
    widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase());
 
104
 
 
105
    // We need a config for HTML_PARSER to work.
 
106
    config = config || {};
 
107
 
 
108
    Widget.superclass.constructor.call(widget, config);
 
109
 
 
110
    render = widget.get(RENDER);
 
111
 
 
112
    if (render) {
 
113
        // Render could be a node or boolean
 
114
        if (render !== TRUE) {
 
115
            parentNode = render;
 
116
        }
 
117
        widget.render(parentNode);
 
118
    }
 
119
}
 
120
 
 
121
/**
 
122
 * Static property provides a string to identify the class.
 
123
 * <p>
 
124
 * Currently used to apply class identifiers to the bounding box 
 
125
 * and to classify events fired by the widget.
 
126
 * </p>
 
127
 *
 
128
 * @property NAME
 
129
 * @type String
 
130
 * @static
 
131
 */
 
132
Widget.NAME = "widget";
 
133
 
 
134
/**
 
135
 * Constant used to identify state changes originating from
 
136
 * the DOM (as opposed to the JavaScript model).
 
137
 *
 
138
 * @property UI_SRC
 
139
 * @type String
 
140
 * @static
 
141
 * @final
 
142
 */
 
143
UI = Widget.UI_SRC = "ui";
 
144
 
 
145
/**
 
146
 * Static property used to define the default attribute 
 
147
 * configuration for the Widget.
 
148
 * 
 
149
 * @property ATTRS
 
150
 * @type Object
 
151
 * @static
 
152
 */
 
153
Widget.ATTRS = ATTRS;
 
154
 
 
155
// Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd
 
156
 
 
157
/**
 
158
 * @attribute id
 
159
 * @writeOnce
 
160
 * @default Generated using guid()
 
161
 * @type String
 
162
 */
 
163
 
 
164
ATTRS[ID] = {
 
165
    valueFn: "_guid",
 
166
    writeOnce: TRUE
 
167
};
 
168
 
 
169
/**
 
170
 * Flag indicating whether or not this Widget
 
171
 * has been through the render lifecycle phase.
 
172
 *
 
173
 * @attribute rendered
 
174
 * @readOnly
 
175
 * @default false
 
176
 * @type boolean
 
177
 */
 
178
ATTRS[RENDERED] = {
 
179
    value:FALSE,
 
180
    readOnly: TRUE
 
181
};
 
182
 
 
183
/**
 
184
 * @attribute boundingBox
 
185
 * @description The outermost DOM node for the Widget, used for sizing and positioning 
 
186
 * of a Widget as well as a containing element for any decorator elements used 
 
187
 * for skinning.
 
188
 * @type String | Node
 
189
 * @writeOnce
 
190
 */
 
191
ATTRS[BOUNDING_BOX] = {
 
192
    value:null,
 
193
    setter: "_setBB",
 
194
    writeOnce: TRUE
 
195
};
 
196
 
 
197
/**
 
198
 * @attribute contentBox
 
199
 * @description A DOM node that is a direct descendant of a Widget's bounding box that 
 
200
 * houses its content.
 
201
 * @type String | Node
 
202
 * @writeOnce
 
203
 */
 
204
ATTRS[CONTENT_BOX] = {
 
205
    valueFn:"_defaultCB",
 
206
    setter: "_setCB",
 
207
    writeOnce: TRUE
 
208
};
 
209
 
 
210
/**
 
211
 * @attribute tabIndex
 
212
 * @description Number (between -32767 to 32767) indicating the widget's 
 
213
 * position in the default tab flow.  The value is used to set the 
 
214
 * "tabIndex" attribute on the widget's bounding box.  Negative values allow
 
215
 * the widget to receive DOM focus programmatically (by calling the focus
 
216
 * method), while being removed from the default tab flow.  A value of 
 
217
 * null removes the "tabIndex" attribute from the widget's bounding box.
 
218
 * @type Number
 
219
 * @default null
 
220
 */
 
221
ATTRS[TAB_INDEX] = {
 
222
    value: null,
 
223
    validator: "_validTabIndex"
 
224
};
 
225
 
 
226
/**
 
227
 * @attribute focused
 
228
 * @description Boolean indicating if the Widget, or one of its descendants, 
 
229
 * has focus.
 
230
 * @readOnly
 
231
 * @default false
 
232
 * @type boolean
 
233
 */
 
234
ATTRS[FOCUSED] = {
 
235
    value: FALSE,
 
236
    readOnly:TRUE
 
237
};
 
238
 
 
239
/**
 
240
 * @attribute disabled
 
241
 * @description Boolean indicating if the Widget should be disabled. The disabled implementation
 
242
 * is left to the specific classes extending widget.
 
243
 * @default false
 
244
 * @type boolean
 
245
 */
 
246
ATTRS[DISABLED] = {
 
247
    value: FALSE
 
248
};
 
249
 
 
250
/**
 
251
 * @attribute visible
 
252
 * @description Boolean indicating weather or not the Widget is visible.
 
253
 * @default TRUE
 
254
 * @type boolean
 
255
 */
 
256
ATTRS[VISIBLE] = {
 
257
    value: TRUE
 
258
};
 
259
 
 
260
/**
 
261
 * @attribute height
 
262
 * @description String with units, or number, representing the height of the Widget. If a number is provided,
 
263
 * the default unit, defined by the Widgets DEF_UNIT, property is used.
 
264
 * @default EMPTY_STR
 
265
 * @type {String | Number}
 
266
 */
 
267
ATTRS[HEIGHT] = {
 
268
    value: EMPTY_STR
 
269
};
 
270
 
 
271
/**
 
272
 * @attribute width
 
273
 * @description String with units, or number, representing the width of the Widget. If a number is provided,
 
274
 * the default unit, defined by the Widgets DEF_UNIT, property is used.
 
275
 * @default EMPTY_STR
 
276
 * @type {String | Number}
 
277
 */
 
278
ATTRS[WIDTH] = {
 
279
    value: EMPTY_STR
 
280
};
 
281
 
 
282
/**
 
283
 * @attribute strings
 
284
 * @description Collection of strings used to label elements of the Widget's UI.
 
285
 * @default null
 
286
 * @type Object
 
287
 */
 
288
ATTRS[STRINGS] = {
 
289
    value: {},
 
290
    setter: "_strSetter",
 
291
    getter: "_strGetter"
 
292
};
 
293
 
 
294
/**
 
295
 * Whether or not to render the widget automatically after init, and optionally, to which parent node.
 
296
 *
 
297
 * @attribute render
 
298
 * @type boolean | Node
 
299
 * @writeOnce
 
300
 */
 
301
ATTRS[RENDER] = {
 
302
    value:FALSE,
 
303
    writeOnce:TRUE
 
304
};
 
305
 
 
306
/**
 
307
 * The css prefix which the static Widget.getClassName method should use when constructing class names
 
308
 *
 
309
 * @property CSS_PREFIX
 
310
 * @type String
 
311
 * @default Widget.NAME.toLowerCase()
 
312
 * @private
 
313
 * @static
 
314
 */
 
315
Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase());
 
316
 
 
317
/**
 
318
 * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined
 
319
 * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and 
 
320
 * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for 
 
321
 * the prefix and widget class name).
 
322
 * <p>
 
323
 * The instance based version of this method can be used to generate standard prefixed classnames,
 
324
 * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you
 
325
 * need to use a constant class name across different types instances.
 
326
 * </p>
 
327
 * @method getClassName
 
328
 * @param {String*} args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name
 
329
 */
 
330
Widget.getClassName = function() {
 
331
    // arguments needs to be array'fied to concat
 
332
    return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true));
 
333
};
 
334
 
 
335
_getWidgetClassName = Widget.getClassName;
 
336
 
 
337
/**
 
338
 * Returns the widget instance whose bounding box contains, or is, the given node. 
 
339
 * <p>
 
340
 * In the case of nested widgets, the nearest bounding box ancestor is used to
 
341
 * return the widget instance.
 
342
 * </p>
 
343
 * @method getByNode
 
344
 * @static
 
345
 * @param node {Node | String} The node for which to return a Widget instance. If a selector
 
346
 * string is passed in, which selects more than one node, the first node found is used.
 
347
 * @return {Widget} Widget instance, or null if not found.
 
348
 */
 
349
Widget.getByNode = function(node) {
 
350
    var widget,
 
351
        nodeid,
 
352
        widgetMarker = _getWidgetClassName();
 
353
 
 
354
    node = Node.one(node);
 
355
    if (node) {
 
356
        node = node.ancestor("." + widgetMarker, true);
 
357
        if (node) {
 
358
            nodeid = node.get(ID);
 
359
            widget = _instances[nodeid];
 
360
        }
 
361
    }
 
362
 
 
363
    return widget || null;
 
364
};
 
365
 
 
366
Y.extend(Widget, Y.Base, {
 
367
 
 
368
    /**
 
369
     * Returns a class name prefixed with the the value of the 
 
370
     * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property.
 
371
     * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings.
 
372
     * e.g. 
 
373
     * <code>
 
374
     * <pre>
 
375
     *    // returns "yui-slider-foo-bar", for a slider instance
 
376
     *    var scn = slider.getClassName('foo','bar');
 
377
     *
 
378
     *    // returns "yui-overlay-foo-bar", for an overlay instance
 
379
     *    var ocn = overlay.getClassName('foo','bar');
 
380
     * </pre>
 
381
     * </code>
 
382
     *
 
383
     * @method getClassName
 
384
     * @param {String}+ One or more classname bits to be joined and prefixed
 
385
     */
 
386
    getClassName: function () {
 
387
        return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true));
 
388
    },
 
389
 
 
390
    /**
 
391
     * Initializer lifecycle implementation for the Widget class. Registers the 
 
392
     * widget instance, and runs through the Widget's HTML_PARSER definition. 
 
393
     *
 
394
     * @method initializer
 
395
     * @protected
 
396
     * @param  config {Object} Configuration object literal for the widget
 
397
     */
 
398
    initializer: function(config) {
 
399
        Y.log('initializer called', 'life', 'widget');
 
400
 
 
401
        var bb = this.get(BOUNDING_BOX);
 
402
        if (bb instanceof Node) {
 
403
            this._mapInstance(bb.get(ID));
 
404
        }
 
405
 
 
406
        /**
 
407
         * Notification event, which widget implementations can fire, when
 
408
         * they change the content of the widget. This event has no default
 
409
         * behavior and cannot be prevented, so the "on" or "after"
 
410
         * moments are effectively equivalent (with on listeners being invoked before 
 
411
         * after listeners).
 
412
         *
 
413
         * @event widget:contentUpdate
 
414
         * @preventable false
 
415
         * @param {EventFacade} e The Event Facade
 
416
         */
 
417
 
 
418
        if (this._applyParser) {
 
419
            this._applyParser(config);
 
420
        }
 
421
    },
 
422
 
 
423
    /**
 
424
     * Utility method used to add an entry to the boundingBox id to instance map. 
 
425
     *
 
426
     * This method can be used to populate the instance with lazily created boundingBox Node references. 
 
427
     *
 
428
     * @method _mapInstance
 
429
     * @param {String} The boundingBox id
 
430
     * @protected
 
431
     */
 
432
    _mapInstance : function(id) {
 
433
        if (!(_instances[id])) {
 
434
            _instances[id] = this;
 
435
        }
 
436
    },
 
437
 
 
438
    /**
 
439
     * Destructor lifecycle implementation for the Widget class. Purges events attached
 
440
     * to the bounding box and content box, removes them from the DOM and removes 
 
441
     * the Widget from the list of registered widgets.
 
442
     *
 
443
     * @method destructor
 
444
     * @protected
 
445
     */
 
446
    destructor: function() {
 
447
        Y.log('destructor called', 'life', 'widget');
 
448
 
 
449
        var boundingBox = this.get(BOUNDING_BOX),
 
450
            bbid;
 
451
 
 
452
        if (boundingBox instanceof Node) {
 
453
            bbid = boundingBox.get(ID);
 
454
 
 
455
            if (bbid in _instances) {
 
456
                delete _instances[bbid];
 
457
            }
 
458
 
 
459
            this._destroyBox();
 
460
        }
 
461
    },
 
462
 
 
463
    /**
 
464
     * <p>
 
465
     * Destroy lifecycle method. Fires the destroy
 
466
     * event, prior to invoking destructors for the
 
467
     * class hierarchy.
 
468
     *
 
469
     * Overrides Base's implementation, to support arguments to destroy
 
470
     * </p>
 
471
     * <p>
 
472
     * Subscribers to the destroy
 
473
     * event can invoke preventDefault on the event object, to prevent destruction
 
474
     * from proceeding.
 
475
     * </p>
 
476
     * @method destroy
 
477
     * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are removed and destroyed. Defaults to false due to potentially high run-time cost. 
 
478
     * @return {Widget} A reference to this object
 
479
     * @chainable
 
480
     */
 
481
    destroy: function(destroyAllNodes) {
 
482
        this._destroyAllNodes = destroyAllNodes;
 
483
        return Widget.superclass.destroy.apply(this);
 
484
    },
 
485
 
 
486
    /**
 
487
     * Removes and destroys the widgets rendered boundingBox, contentBox,
 
488
     * and detaches bound UI events.
 
489
     *
 
490
     * @method _destroyBox
 
491
     * @protected 
 
492
     */
 
493
    _destroyBox : function() {
 
494
 
 
495
        var boundingBox = this.get(BOUNDING_BOX),
 
496
            contentBox = this.get(CONTENT_BOX),
 
497
            deep = this._destroyAllNodes,
 
498
            same;
 
499
 
 
500
        same = boundingBox && boundingBox.compareTo(contentBox);
 
501
 
 
502
        if (this.UI_EVENTS) {
 
503
            this._destroyUIEvents();
 
504
        }
 
505
 
 
506
        this._unbindUI(boundingBox);
 
507
 
 
508
        if (deep) {
 
509
            // Removes and destroys all child nodes.
 
510
            boundingBox.empty();
 
511
            boundingBox.remove(TRUE);
 
512
        } else {
 
513
            if (contentBox) {
 
514
                contentBox.remove(TRUE);
 
515
            }
 
516
            if (!same) {
 
517
                boundingBox.remove(TRUE);
 
518
            }
 
519
        }
 
520
    },
 
521
 
 
522
    /**
 
523
     * Establishes the initial DOM for the widget. Invoking this
 
524
     * method will lead to the creating of all DOM elements for
 
525
     * the widget (or the manipulation of existing DOM elements 
 
526
     * for the progressive enhancement use case).
 
527
     * <p>
 
528
     * This method should only be invoked once for an initialized
 
529
     * widget.
 
530
     * </p>
 
531
     * <p>
 
532
     * It delegates to the widget specific renderer method to do
 
533
     * the actual work.
 
534
     * </p>
 
535
     *
 
536
     * @method render
 
537
     * @chainable
 
538
     * @final 
 
539
     * @param  parentNode {Object | String} Optional. The Node under which the 
 
540
     * Widget is to be rendered. This can be a Node instance or a CSS selector string. 
 
541
     * <p>
 
542
     * If the selector string returns more than one Node, the first node will be used 
 
543
     * as the parentNode. NOTE: This argument is required if both the boundingBox and contentBox
 
544
     * are not currently in the document. If it's not provided, the Widget will be rendered
 
545
     * to the body of the current document in this case.
 
546
     * </p>
 
547
     */
 
548
    render: function(parentNode) {
 
549
        if (this.get(DESTROYED)) { Y.log("Render failed; widget has been destroyed", "error", "widget"); }
 
550
 
 
551
        if (!this.get(DESTROYED) && !this.get(RENDERED)) {
 
552
             /**
 
553
              * Lifecycle event for the render phase, fired prior to rendering the UI 
 
554
              * for the widget (prior to invoking the widget's renderer method).
 
555
              * <p>
 
556
              * Subscribers to the "on" moment of this event, will be notified 
 
557
              * before the widget is rendered.
 
558
              * </p>
 
559
              * <p>
 
560
              * Subscribers to the "after" moment of this event, will be notified
 
561
              * after rendering is complete.
 
562
              * </p>
 
563
              *
 
564
              * @event widget:render
 
565
              * @preventable _defRenderFn
 
566
              * @param {EventFacade} e The Event Facade
 
567
              */
 
568
            this.publish(RENDER, {
 
569
                queuable:FALSE,
 
570
                fireOnce:TRUE,
 
571
                defaultTargetOnly:TRUE,
 
572
                defaultFn: this._defRenderFn
 
573
            });
 
574
 
 
575
            this.fire(RENDER, {parentNode: (parentNode) ? Node.one(parentNode) : null});
 
576
        }
 
577
        return this;
 
578
    },
 
579
 
 
580
    /**
 
581
     * Default render handler
 
582
     *
 
583
     * @method _defRenderFn
 
584
     * @protected
 
585
     * @param {EventFacade} e The Event object
 
586
     * @param {Node} parentNode The parent node to render to, if passed in to the <code>render</code> method
 
587
     */
 
588
    _defRenderFn : function(e) {
 
589
        this._parentNode = e.parentNode;
 
590
         
 
591
        this.renderer();
 
592
        this._set(RENDERED, TRUE);
 
593
 
 
594
        this._removeLoadingClassNames();
 
595
    },
 
596
 
 
597
    /**
 
598
     * Creates DOM (or manipulates DOM for progressive enhancement)
 
599
     * This method is invoked by render() and is not chained 
 
600
     * automatically for the class hierarchy (unlike initializer, destructor) 
 
601
     * so it should be chained manually for subclasses if required.
 
602
     *
 
603
     * @method renderer
 
604
     * @protected
 
605
     */
 
606
    renderer: function() {
 
607
        // kweight
 
608
        var widget = this;
 
609
 
 
610
        widget._renderUI();
 
611
        widget.renderUI();
 
612
 
 
613
        widget._bindUI();
 
614
        widget.bindUI();
 
615
 
 
616
        widget._syncUI();
 
617
        widget.syncUI();
 
618
    },
 
619
 
 
620
    /**
 
621
     * Configures/Sets up listeners to bind Widget State to UI/DOM
 
622
     * 
 
623
     * This method is not called by framework and is not chained 
 
624
     * automatically for the class hierarchy.
 
625
     * 
 
626
     * @method bindUI
 
627
     * @protected
 
628
     */
 
629
    bindUI: EMPTY_FN,
 
630
 
 
631
    /**
 
632
     * Adds nodes to the DOM 
 
633
     * 
 
634
     * This method is not called by framework and is not chained 
 
635
     * automatically for the class hierarchy.
 
636
     * 
 
637
     * @method renderUI
 
638
     * @protected
 
639
     */
 
640
    renderUI: EMPTY_FN,
 
641
 
 
642
    /**
 
643
     * Refreshes the rendered UI, based on Widget State
 
644
     * 
 
645
     * This method is not called by framework and is not chained
 
646
     * automatically for the class hierarchy.
 
647
     *
 
648
     * @method syncUI
 
649
     * @protected
 
650
     *
 
651
     */
 
652
    syncUI: EMPTY_FN,
 
653
 
 
654
    /**
 
655
     * @method hide
 
656
     * @description Hides the Widget by setting the "visible" attribute to "false".
 
657
     * @chainable
 
658
     */
 
659
    hide: function() {
 
660
        return this.set(VISIBLE, FALSE);
 
661
    },
 
662
 
 
663
    /**
 
664
     * @method show
 
665
     * @description Shows the Widget by setting the "visible" attribute to "true".
 
666
     * @chainable
 
667
     */
 
668
    show: function() {
 
669
        return this.set(VISIBLE, TRUE);
 
670
    },
 
671
 
 
672
    /**
 
673
     * @method focus
 
674
     * @description Causes the Widget to receive the focus by setting the "focused" 
 
675
     * attribute to "true".
 
676
     * @chainable
 
677
     */
 
678
    focus: function () {
 
679
        return this._set(FOCUSED, TRUE);
 
680
    },
 
681
 
 
682
    /**
 
683
     * @method blur
 
684
     * @description Causes the Widget to lose focus by setting the "focused" attribute 
 
685
     * to "false"
 
686
     * @chainable
 
687
     */
 
688
    blur: function () {
 
689
        return this._set(FOCUSED, FALSE);
 
690
    },
 
691
 
 
692
    /**
 
693
     * @method enable
 
694
     * @description Set the Widget's "disabled" attribute to "false".
 
695
     * @chainable
 
696
     */
 
697
    enable: function() {
 
698
        return this.set(DISABLED, FALSE);
 
699
    },
 
700
 
 
701
    /**
 
702
     * @method disable
 
703
     * @description Set the Widget's "disabled" attribute to "true".
 
704
     * @chainable
 
705
     */
 
706
    disable: function() {
 
707
        return this.set(DISABLED, TRUE);
 
708
    },
 
709
 
 
710
    /**
 
711
     * @method _uiSizeCB
 
712
     * @protected
 
713
     * @param {boolean} expand
 
714
     */
 
715
    _uiSizeCB : function(expand) {
 
716
        this.get(CONTENT_BOX).toggleClass(_getWidgetClassName(CONTENT, "expanded"), expand);        
 
717
    },
 
718
 
 
719
    /**
 
720
     * Helper method to collect the boundingBox and contentBox and append to the provided parentNode, if not
 
721
     * already a child. The owner document of the boundingBox, or the owner document of the contentBox will be used 
 
722
     * as the document into which the Widget is rendered if a parentNode is node is not provided. If both the boundingBox and
 
723
     * the contentBox are not currently in the document, and no parentNode is provided, the widget will be rendered 
 
724
     * to the current document's body.
 
725
     *
 
726
     * @method _renderBox
 
727
     * @private
 
728
     * @param {Node} parentNode The parentNode to render the widget to. If not provided, and both the boundingBox and
 
729
     * the contentBox are not currently in the document, the widget will be rendered to the current document's body.
 
730
     */
 
731
    _renderBox: function(parentNode) {
 
732
 
 
733
        // TODO: Performance Optimization [ More effective algo to reduce Node refs, compares, replaces? ]
 
734
 
 
735
        var widget = this, // kweight
 
736
            contentBox = widget.get(CONTENT_BOX),
 
737
            boundingBox = widget.get(BOUNDING_BOX),
 
738
            srcNode = widget.get(SRC_NODE),
 
739
            defParentNode = widget.DEF_PARENT_NODE,
 
740
 
 
741
            doc = (srcNode && srcNode.get(OWNER_DOCUMENT)) || boundingBox.get(OWNER_DOCUMENT) || contentBox.get(OWNER_DOCUMENT);
 
742
 
 
743
        // If srcNode (assume it's always in doc), have contentBox take its place (widget render responsible for re-use of srcNode contents)
 
744
        if (srcNode && !srcNode.compareTo(contentBox) && !contentBox.inDoc(doc)) {
 
745
            srcNode.replace(contentBox);
 
746
        }
 
747
 
 
748
        if (!boundingBox.compareTo(contentBox.get(PARENT_NODE)) && !boundingBox.compareTo(contentBox)) {
 
749
            // If contentBox box is already in the document, have boundingBox box take it's place
 
750
            if (contentBox.inDoc(doc)) {
 
751
                contentBox.replace(boundingBox);
 
752
            }
 
753
            boundingBox.appendChild(contentBox);
 
754
        }
 
755
 
 
756
        parentNode = parentNode || (defParentNode && Node.one(defParentNode));
 
757
 
 
758
        if (parentNode) {
 
759
            parentNode.appendChild(boundingBox);
 
760
        } else if (!boundingBox.inDoc(doc)) {
 
761
            Node.one(BODY).insert(boundingBox, 0);
 
762
        }
 
763
    },
 
764
 
 
765
    /**
 
766
     * Setter for the boundingBox attribute
 
767
     *
 
768
     * @method _setBB
 
769
     * @private
 
770
     * @param Node/String
 
771
     * @return Node
 
772
     */
 
773
    _setBB: function(node) {
 
774
        return this._setBox(this.get(ID), node, this.BOUNDING_TEMPLATE);
 
775
    },
 
776
 
 
777
    /**
 
778
     * Setter for the contentBox attribute
 
779
     *
 
780
     * @method _setCB
 
781
     * @private
 
782
     * @param {Node|String} node
 
783
     * @return Node
 
784
     */
 
785
    _setCB: function(node) {
 
786
        return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE);
 
787
    },
 
788
 
 
789
    /**
 
790
     * Returns the default value for the contentBox attribute. 
 
791
     *
 
792
     * For the Widget class, this will be the srcNode if provided, otherwise null (resulting in
 
793
     * a new contentBox node instance being created)
 
794
     *
 
795
     * @method _defaultCB
 
796
     * @protected
 
797
     */
 
798
    _defaultCB : function(node) {
 
799
        return this.get(SRC_NODE) || null;
 
800
    },
 
801
 
 
802
    /**
 
803
     * Helper method to set the bounding/content box, or create it from
 
804
     * the provided template if not found.
 
805
     *
 
806
     * @method _setBox
 
807
     * @private
 
808
     *
 
809
     * @param {String} id The node's id attribute
 
810
     * @param {Node|String} node The node reference
 
811
     * @param {String} template HTML string template for the node
 
812
     * @return {Node} The node
 
813
     */
 
814
    _setBox : function(id, node, template) {
 
815
        node = Node.one(node) || Node.create(template);
 
816
        if (!node.get(ID)) {
 
817
            node.set(ID, id || Y.guid());
 
818
        }
 
819
        return node;
 
820
    },
 
821
 
 
822
    /**
 
823
     * Initializes the UI state for the Widget's bounding/content boxes.
 
824
     *
 
825
     * @method _renderUI
 
826
     * @protected
 
827
     */
 
828
    _renderUI: function() {
 
829
        this._renderBoxClassNames();
 
830
        this._renderBox(this._parentNode);
 
831
    },
 
832
 
 
833
    /**
 
834
     * Applies standard class names to the boundingBox and contentBox
 
835
     *
 
836
     * @method _renderBoxClassNames
 
837
     * @protected
 
838
     */
 
839
    _renderBoxClassNames : function() {
 
840
        var classes = this._getClasses(),
 
841
            cl,
 
842
            boundingBox = this.get(BOUNDING_BOX),
 
843
            i;
 
844
 
 
845
        boundingBox.addClass(_getWidgetClassName());
 
846
 
 
847
        // Start from Widget Sub Class
 
848
        for (i = classes.length-3; i >= 0; i--) {
 
849
            cl = classes[i];
 
850
            boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase()));
 
851
        }
 
852
 
 
853
        // Use instance based name for content box
 
854
        this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT));
 
855
    },
 
856
 
 
857
    /**
 
858
     * Removes class names representative of the widget's loading state from 
 
859
     * the boundingBox.
 
860
     *
 
861
     * @method _removeLoadingClassNames
 
862
     * @protected
 
863
     */
 
864
    _removeLoadingClassNames: function () {
 
865
 
 
866
        var boundingBox = this.get(BOUNDING_BOX),
 
867
            contentBox = this.get(CONTENT_BOX),
 
868
            instClass = this.getClassName(LOADING),
 
869
            widgetClass = _getWidgetClassName(LOADING);
 
870
 
 
871
        boundingBox.removeClass(widgetClass)
 
872
                   .removeClass(instClass);
 
873
 
 
874
        contentBox.removeClass(widgetClass)
 
875
                  .removeClass(instClass);
 
876
    },
 
877
 
 
878
    /**
 
879
     * Sets up DOM and CustomEvent listeners for the widget.
 
880
     *
 
881
     * @method _bindUI
 
882
     * @protected
 
883
     */
 
884
    _bindUI: function() {
 
885
        this._bindAttrUI(this._UI_ATTRS.BIND);
 
886
        this._bindDOM();
 
887
    },
 
888
 
 
889
    /**
 
890
     * @method _unbindUI
 
891
     * @protected
 
892
     */
 
893
    _unbindUI : function(boundingBox) {
 
894
        this._unbindDOM(boundingBox);
 
895
    },
 
896
 
 
897
    /**
 
898
     * Sets up DOM listeners, on elements rendered by the widget.
 
899
     * 
 
900
     * @method _bindDOM
 
901
     * @protected
 
902
     */
 
903
    _bindDOM : function() {
 
904
        var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT),
 
905
            focusHandle = Widget._hDocFocus;
 
906
 
 
907
        // Shared listener across all Widgets.
 
908
        if (!focusHandle) {
 
909
            focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this);
 
910
            focusHandle.listeners = {
 
911
                count: 0
 
912
            };
 
913
        }
 
914
 
 
915
        focusHandle.listeners[Y.stamp(this, true)] = true;
 
916
        focusHandle.listeners.count++;
 
917
 
 
918
        //      Fix for Webkit:
 
919
        //      Document doesn't receive focus in Webkit when the user mouses 
 
920
        //      down on it, so the "focused" attribute won't get set to the 
 
921
        //      correct value. Keeping this instance based for now, potential better performance.
 
922
        //  Otherwise we'll end up looking up widgets from the DOM on every mousedown.
 
923
        if (WEBKIT){
 
924
            this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this);
 
925
        }
 
926
    },
 
927
 
 
928
    /**
 
929
     * @method _unbindDOM
 
930
     * @protected
 
931
     */   
 
932
    _unbindDOM : function(boundingBox) {
 
933
 
 
934
        var focusHandle = Widget._hDocFocus,
 
935
            yuid = Y.stamp(this, true),
 
936
            focusListeners,
 
937
            mouseHandle = this._hDocMouseDown;
 
938
 
 
939
        if (focusHandle) {
 
940
 
 
941
            focusListeners = focusHandle.listeners;
 
942
 
 
943
            if (focusListeners[yuid]) {
 
944
                delete focusListeners[yuid];
 
945
                focusListeners.count--;
 
946
            }
 
947
 
 
948
            if (focusListeners.count === 0) {
 
949
                focusHandle.detach();
 
950
                Widget._hDocFocus = null;
 
951
            }
 
952
        }
 
953
 
 
954
        if (WEBKIT && mouseHandle) {
 
955
            mouseHandle.detach();
 
956
        }
 
957
    },
 
958
 
 
959
    /**
 
960
     * Updates the widget UI to reflect the attribute state.
 
961
     *
 
962
     * @method _syncUI
 
963
     * @protected
 
964
     */
 
965
    _syncUI: function() {
 
966
        this._syncAttrUI(this._UI_ATTRS.SYNC);
 
967
    },
 
968
 
 
969
    /**
 
970
     * Sets the height on the widget's bounding box element
 
971
     *
 
972
     * @method _uiSetHeight
 
973
     * @protected
 
974
     * @param {String | Number} val
 
975
     */
 
976
    _uiSetHeight: function(val) {
 
977
        this._uiSetDim(HEIGHT, val);
 
978
        this._uiSizeCB((val !== EMPTY_STR && val !== AUTO));
 
979
    },
 
980
 
 
981
    /**
 
982
     * Sets the width on the widget's bounding box element
 
983
     *
 
984
     * @method _uiSetWidth
 
985
     * @protected
 
986
     * @param {String | Number} val
 
987
     */
 
988
    _uiSetWidth: function(val) {
 
989
        this._uiSetDim(WIDTH, val);
 
990
    },
 
991
 
 
992
    /**
 
993
     * @method _uiSetDim
 
994
     * @private
 
995
     * @param {String} dim The dimension - "width" or "height"
 
996
     * @param {Number | String} val The value to set
 
997
     */
 
998
    _uiSetDim: function(dimension, val) {
 
999
        this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val);
 
1000
    },
 
1001
 
 
1002
    /**
 
1003
     * Sets the visible state for the UI
 
1004
     * 
 
1005
     * @method _uiSetVisible
 
1006
     * @protected
 
1007
     * @param {boolean} val
 
1008
     */
 
1009
    _uiSetVisible: function(val) {
 
1010
        this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val);
 
1011
    },
 
1012
 
 
1013
    /**
 
1014
     * Sets the disabled state for the UI
 
1015
     *
 
1016
     * @method _uiSetDisabled
 
1017
     * @protected
 
1018
     * @param {boolean} val
 
1019
     */
 
1020
    _uiSetDisabled: function(val) {
 
1021
        this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val);
 
1022
    },
 
1023
 
 
1024
    /**
 
1025
     * Sets the focused state for the UI
 
1026
     *
 
1027
     * @method _uiSetFocused
 
1028
     * @protected
 
1029
     * @param {boolean} val
 
1030
     * @param {string} src String representing the source that triggered an update to 
 
1031
     * the UI.     
 
1032
     */
 
1033
    _uiSetFocused: function(val, src) {
 
1034
         var boundingBox = this.get(BOUNDING_BOX);
 
1035
         boundingBox.toggleClass(this.getClassName(FOCUSED), val);
 
1036
 
 
1037
         if (src !== UI) {
 
1038
            if (val) {
 
1039
                boundingBox.focus();  
 
1040
            } else {
 
1041
                boundingBox.blur();
 
1042
            }
 
1043
         }
 
1044
    },
 
1045
 
 
1046
    /**
 
1047
     * Set the tabIndex on the widget's rendered UI
 
1048
     *
 
1049
     * @method _uiSetTabIndex
 
1050
     * @protected
 
1051
     * @param Number
 
1052
     */
 
1053
    _uiSetTabIndex: function(index) {
 
1054
        var boundingBox = this.get(BOUNDING_BOX);
 
1055
 
 
1056
        if (L.isNumber(index)) {
 
1057
            boundingBox.set(TAB_INDEX, index);
 
1058
        } else {
 
1059
            boundingBox.removeAttribute(TAB_INDEX);
 
1060
        }
 
1061
    },
 
1062
 
 
1063
    /**
 
1064
     * @method _onDocMouseDown
 
1065
     * @description "mousedown" event handler for the owner document of the 
 
1066
     * widget's bounding box.
 
1067
     * @protected
 
1068
     * @param {EventFacade} evt The event facade for the DOM focus event
 
1069
     */
 
1070
    _onDocMouseDown: function (evt) {
 
1071
        if (this._domFocus) {
 
1072
            this._onDocFocus(evt);
 
1073
        }
 
1074
    },
 
1075
 
 
1076
    /**
 
1077
     * DOM focus event handler, used to sync the state of the Widget with the DOM
 
1078
     * 
 
1079
     * @method _onDocFocus
 
1080
     * @protected
 
1081
     * @param {EventFacade} evt The event facade for the DOM focus event
 
1082
     */
 
1083
    _onDocFocus: function (evt) {
 
1084
        var widget = Widget.getByNode(evt.target),
 
1085
            activeWidget = Widget._active;
 
1086
 
 
1087
        if (activeWidget && (activeWidget !== widget)) {
 
1088
            activeWidget._domFocus = false;
 
1089
            activeWidget._set(FOCUSED, false, {src:UI});
 
1090
 
 
1091
            Widget._active = null;
 
1092
        }
 
1093
 
 
1094
        if (widget) {
 
1095
            widget._domFocus = true;
 
1096
            widget._set(FOCUSED, true, {src:UI});
 
1097
 
 
1098
            Widget._active = widget;
 
1099
        }
 
1100
    },
 
1101
 
 
1102
    /**
 
1103
     * Generic toString implementation for all widgets.
 
1104
     *
 
1105
     * @method toString
 
1106
     * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ]
 
1107
     */
 
1108
    toString: function() {
 
1109
        // Using deprecated name prop for kweight squeeze.
 
1110
        return this.name + "[" + this.get(ID) + "]";
 
1111
    },
 
1112
 
 
1113
    /**
 
1114
     * Default unit to use for dimension values
 
1115
     * 
 
1116
     * @property DEF_UNIT
 
1117
     * @type String
 
1118
     */
 
1119
    DEF_UNIT : "px",
 
1120
 
 
1121
    /** 
 
1122
     * Default node to render the bounding box to. If not set,
 
1123
     * will default to the current document body.
 
1124
     * 
 
1125
     * @property DEF_PARENT_NODE
 
1126
     * @type String | Node
 
1127
     */ 
 
1128
    DEF_PARENT_NODE : null,
 
1129
 
 
1130
    /**
 
1131
     * Property defining the markup template for content box. If your Widget doesn't
 
1132
     * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null,
 
1133
     * and contentBox and boundingBox will both point to the same Node. 
 
1134
     *
 
1135
     * @property CONTENT_TEMPLATE
 
1136
     * @type String
 
1137
     */
 
1138
    CONTENT_TEMPLATE : DIV,
 
1139
 
 
1140
    /**
 
1141
     * Property defining the markup template for bounding box.
 
1142
     *
 
1143
     * @property BOUNDING_TEMPLATE
 
1144
     * @type String
 
1145
     */
 
1146
    BOUNDING_TEMPLATE : DIV,
 
1147
 
 
1148
    /**
 
1149
     * @method _guid
 
1150
     * @protected
 
1151
     */
 
1152
    _guid : function() {
 
1153
        return Y.guid();
 
1154
    },
 
1155
 
 
1156
    /**
 
1157
     * @method _validTabIndex
 
1158
     * @protected
 
1159
     * @param {Number} tabIndex
 
1160
     */
 
1161
    _validTabIndex : function (tabIndex) {
 
1162
        return (L.isNumber(tabIndex) || L.isNull(tabIndex));
 
1163
    },
 
1164
 
 
1165
    /**
 
1166
     * Binds after listeners for the list of attributes provided
 
1167
     * 
 
1168
     * @method _bindAttrUI
 
1169
     * @private
 
1170
     * @param {Array} attrs
 
1171
     */
 
1172
    _bindAttrUI : function(attrs) {
 
1173
        var i, 
 
1174
            l = attrs.length; 
 
1175
 
 
1176
        for (i = 0; i < l; i++) {
 
1177
            this.after(attrs[i] + CHANGE, this._setAttrUI);
 
1178
        }
 
1179
    },
 
1180
 
 
1181
    /**
 
1182
     * Invokes the _uiSet&#61;ATTR NAME&#62; method for the list of attributes provided  
 
1183
     *
 
1184
     * @method _syncAttrUI
 
1185
     * @private
 
1186
     * @param {Array} attrs
 
1187
     */
 
1188
    _syncAttrUI : function(attrs) {
 
1189
        var i, l = attrs.length, attr;
 
1190
        for (i = 0; i < l; i++) {
 
1191
            attr = attrs[i];
 
1192
            this[_UISET + _toInitialCap(attr)](this.get(attr));
 
1193
        }
 
1194
    },
 
1195
 
 
1196
    /**
 
1197
     * @method _setAttrUI
 
1198
     * @private
 
1199
     * @param {EventFacade} e
 
1200
     */
 
1201
    _setAttrUI : function(e) {
 
1202
        if (e.target === this) {
 
1203
            this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src);
 
1204
        }
 
1205
    },
 
1206
 
 
1207
    /**
 
1208
     * The default setter for the strings attribute. Merges partial sets
 
1209
     * into the full string set, to allow users to partial sets of strings  
 
1210
     *
 
1211
     * @method _strSetter
 
1212
     * @protected
 
1213
     * @param {Object} strings
 
1214
     * @return {String} The full set of strings to set
 
1215
     */
 
1216
    _strSetter : function(strings) {
 
1217
        return Y.merge(this.get(STRINGS), strings);
 
1218
    },
 
1219
 
 
1220
    /**
 
1221
     * Helper method to get a specific string value
 
1222
     *
 
1223
     * @deprecated Used by deprecated WidgetLocale implementations. 
 
1224
     * @method getString
 
1225
     * @param {String} key
 
1226
     * @return {String} The string
 
1227
     */
 
1228
    getString : function(key) {
 
1229
        return this.get(STRINGS)[key];
 
1230
    },
 
1231
 
 
1232
    /**
 
1233
     * Helper method to get the complete set of strings for the widget
 
1234
     *
 
1235
     * @deprecated  Used by deprecated WidgetLocale implementations.
 
1236
     * @method getStrings
 
1237
     * @param {String} key
 
1238
     * @return {String} The strings
 
1239
     */
 
1240
    getStrings : function() {
 
1241
        return this.get(STRINGS);
 
1242
    },
 
1243
 
 
1244
    /**
 
1245
     * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations
 
1246
     *
 
1247
     * @property _UI_ATTRS
 
1248
     * @type Object
 
1249
     * @private
 
1250
     */
 
1251
    _UI_ATTRS : {
 
1252
        BIND: UI_ATTRS,
 
1253
        SYNC: UI_ATTRS
 
1254
    }
 
1255
});
 
1256
 
 
1257
Y.Widget = Widget;
 
1258
 
 
1259
 
 
1260
}, '3.5.1' ,{requires:['attribute', 'event-focus', 'base-base', 'base-pluginhost', 'node-base', 'node-style', 'classnamemanager'], skinnable:true});