~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error

« back to all changes in this revision

Viewing changes to src/webcatalog/static/yui/3.10.3/build/widget-base/widget-base-debug.js

  • Committer: Tarmac
  • Author(s): Stephen Stewart
  • Date: 2013-06-26 09:19:32 UTC
  • mfrom: (184.1.4 ubuntu-global-nav)
  • Revision ID: tarmac-20130626091932-8urtuli368k8p7ds
[r=beuno,jonas-drange] add ubuntu global nav to apps.ubuntu.com

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
YUI 3.10.3 (build 2fb5187)
 
3
Copyright 2013 Yahoo! Inc. All rights reserved.
 
4
Licensed under the BSD License.
 
5
http://yuilibrary.com/license/
 
6
*/
 
7
 
 
8
YUI.add('widget-base', function (Y, NAME) {
 
9
 
 
10
/**
 
11
 * Provides the base Widget class, with HTML Parser support
 
12
 *
 
13
 * @module widget
 
14
 * @main widget
 
15
 */
 
16
 
 
17
/**
 
18
 * Provides the base Widget class
 
19
 *
 
20
 * @module widget
 
21
 * @submodule widget-base
 
22
 */
 
23
var L = Y.Lang,
 
24
    Node = Y.Node,
 
25
 
 
26
    ClassNameManager = Y.ClassNameManager,
 
27
 
 
28
    _getClassName = ClassNameManager.getClassName,
 
29
    _getWidgetClassName,
 
30
 
 
31
    _toInitialCap = Y.cached(function(str) {
 
32
        return str.substring(0, 1).toUpperCase() + str.substring(1);
 
33
    }),
 
34
 
 
35
    // K-Weight, IE GC optimizations
 
36
    CONTENT = "content",
 
37
    VISIBLE = "visible",
 
38
    HIDDEN = "hidden",
 
39
    DISABLED = "disabled",
 
40
    FOCUSED = "focused",
 
41
    WIDTH = "width",
 
42
    HEIGHT = "height",
 
43
    BOUNDING_BOX = "boundingBox",
 
44
    CONTENT_BOX = "contentBox",
 
45
    PARENT_NODE = "parentNode",
 
46
    OWNER_DOCUMENT = "ownerDocument",
 
47
    AUTO = "auto",
 
48
    SRC_NODE = "srcNode",
 
49
    BODY = "body",
 
50
    TAB_INDEX = "tabIndex",
 
51
    ID = "id",
 
52
    RENDER = "render",
 
53
    RENDERED = "rendered",
 
54
    DESTROYED = "destroyed",
 
55
    STRINGS = "strings",
 
56
    DIV = "<div></div>",
 
57
    CHANGE = "Change",
 
58
    LOADING = "loading",
 
59
 
 
60
    _UISET = "_uiSet",
 
61
 
 
62
    EMPTY_STR = "",
 
63
    EMPTY_FN = function() {},
 
64
 
 
65
    TRUE = true,
 
66
    FALSE = false,
 
67
 
 
68
    UI,
 
69
    ATTRS = {},
 
70
    UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX],
 
71
 
 
72
    WEBKIT = Y.UA.webkit,
 
73
 
 
74
    // Widget nodeid-to-instance map.
 
75
    _instances = {};
 
76
 
 
77
/**
 
78
 * A base class for widgets, providing:
 
79
 * <ul>
 
80
 *    <li>The render lifecycle method, in addition to the init and destroy
 
81
 *        lifecycle methods provide by Base</li>
 
82
 *    <li>Abstract methods to support consistent MVC structure across
 
83
 *        widgets: renderer, renderUI, bindUI, syncUI</li>
 
84
 *    <li>Support for common widget attributes, such as boundingBox, contentBox, visible,
 
85
 *        disabled, focused, strings</li>
 
86
 * </ul>
 
87
 *
 
88
 * @param config {Object} Object literal specifying widget configuration properties.
 
89
 *
 
90
 * @class Widget
 
91
 * @constructor
 
92
 * @extends Base
 
93
 */
 
94
function Widget(config) {
 
95
    Y.log('constructor called', 'life', 'widget');
 
96
 
 
97
    // kweight
 
98
    var widget = this,
 
99
        parentNode,
 
100
        render,
 
101
        constructor = widget.constructor;
 
102
 
 
103
    widget._strs = {};
 
104
    widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase());
 
105
 
 
106
    // We need a config for HTML_PARSER to work.
 
107
    config = config || {};
 
108
 
 
109
    Widget.superclass.constructor.call(widget, config);
 
110
 
 
111
    render = widget.get(RENDER);
 
112
 
 
113
    if (render) {
 
114
        // Render could be a node or boolean
 
115
        if (render !== TRUE) {
 
116
            parentNode = render;
 
117
        }
 
118
        widget.render(parentNode);
 
119
    }
 
120
}
 
121
 
 
122
/**
 
123
 * Static property provides a string to identify the class.
 
124
 * <p>
 
125
 * Currently used to apply class identifiers to the bounding box
 
126
 * and to classify events fired by the widget.
 
127
 * </p>
 
128
 *
 
129
 * @property NAME
 
130
 * @type String
 
131
 * @static
 
132
 */
 
133
Widget.NAME = "widget";
 
134
 
 
135
/**
 
136
 * Constant used to identify state changes originating from
 
137
 * the DOM (as opposed to the JavaScript model).
 
138
 *
 
139
 * @property UI_SRC
 
140
 * @type String
 
141
 * @static
 
142
 * @final
 
143
 */
 
144
UI = Widget.UI_SRC = "ui";
 
145
 
 
146
/**
 
147
 * Static property used to define the default attribute
 
148
 * configuration for the Widget.
 
149
 *
 
150
 * @property ATTRS
 
151
 * @type Object
 
152
 * @static
 
153
 */
 
154
Widget.ATTRS = ATTRS;
 
155
 
 
156
// Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd
 
157
 
 
158
/**
 
159
 * @attribute id
 
160
 * @writeOnce
 
161
 * @default Generated using guid()
 
162
 * @type String
 
163
 */
 
164
 
 
165
ATTRS[ID] = {
 
166
    valueFn: "_guid",
 
167
    writeOnce: TRUE
 
168
};
 
169
 
 
170
/**
 
171
 * Flag indicating whether or not this Widget
 
172
 * has been through the render lifecycle phase.
 
173
 *
 
174
 * @attribute rendered
 
175
 * @readOnly
 
176
 * @default false
 
177
 * @type boolean
 
178
 */
 
179
ATTRS[RENDERED] = {
 
180
    value:FALSE,
 
181
    readOnly: TRUE
 
182
};
 
183
 
 
184
/**
 
185
 * @attribute boundingBox
 
186
 * @description The outermost DOM node for the Widget, used for sizing and positioning
 
187
 * of a Widget as well as a containing element for any decorator elements used
 
188
 * for skinning.
 
189
 * @type String | Node
 
190
 * @writeOnce
 
191
 */
 
192
ATTRS[BOUNDING_BOX] = {
 
193
    value:null,
 
194
    setter: "_setBB",
 
195
    writeOnce: TRUE
 
196
};
 
197
 
 
198
/**
 
199
 * @attribute contentBox
 
200
 * @description A DOM node that is a direct descendant of a Widget's bounding box that
 
201
 * houses its content.
 
202
 * @type String | Node
 
203
 * @writeOnce
 
204
 */
 
205
ATTRS[CONTENT_BOX] = {
 
206
    valueFn:"_defaultCB",
 
207
    setter: "_setCB",
 
208
    writeOnce: TRUE
 
209
};
 
210
 
 
211
/**
 
212
 * @attribute tabIndex
 
213
 * @description Number (between -32767 to 32767) indicating the widget's
 
214
 * position in the default tab flow.  The value is used to set the
 
215
 * "tabIndex" attribute on the widget's bounding box.  Negative values allow
 
216
 * the widget to receive DOM focus programmatically (by calling the focus
 
217
 * method), while being removed from the default tab flow.  A value of
 
218
 * null removes the "tabIndex" attribute from the widget's bounding box.
 
219
 * @type Number
 
220
 * @default null
 
221
 */
 
222
ATTRS[TAB_INDEX] = {
 
223
    value: null,
 
224
    validator: "_validTabIndex"
 
225
};
 
226
 
 
227
/**
 
228
 * @attribute focused
 
229
 * @description Boolean indicating if the Widget, or one of its descendants,
 
230
 * has focus.
 
231
 * @readOnly
 
232
 * @default false
 
233
 * @type boolean
 
234
 */
 
235
ATTRS[FOCUSED] = {
 
236
    value: FALSE,
 
237
    readOnly:TRUE
 
238
};
 
239
 
 
240
/**
 
241
 * @attribute disabled
 
242
 * @description Boolean indicating if the Widget should be disabled. The disabled implementation
 
243
 * is left to the specific classes extending widget.
 
244
 * @default false
 
245
 * @type boolean
 
246
 */
 
247
ATTRS[DISABLED] = {
 
248
    value: FALSE
 
249
};
 
250
 
 
251
/**
 
252
 * @attribute visible
 
253
 * @description Boolean indicating whether or not the Widget is visible.
 
254
 * @default TRUE
 
255
 * @type boolean
 
256
 */
 
257
ATTRS[VISIBLE] = {
 
258
    value: TRUE
 
259
};
 
260
 
 
261
/**
 
262
 * @attribute height
 
263
 * @description String with units, or number, representing the height of the Widget. If a number is provided,
 
264
 * the default unit, defined by the Widgets DEF_UNIT, property is used.
 
265
 * @default EMPTY_STR
 
266
 * @type {String | Number}
 
267
 */
 
268
ATTRS[HEIGHT] = {
 
269
    value: EMPTY_STR
 
270
};
 
271
 
 
272
/**
 
273
 * @attribute width
 
274
 * @description String with units, or number, representing the width of the Widget. If a number is provided,
 
275
 * the default unit, defined by the Widgets DEF_UNIT, property is used.
 
276
 * @default EMPTY_STR
 
277
 * @type {String | Number}
 
278
 */
 
279
ATTRS[WIDTH] = {
 
280
    value: EMPTY_STR
 
281
};
 
282
 
 
283
/**
 
284
 * @attribute strings
 
285
 * @description Collection of strings used to label elements of the Widget's UI.
 
286
 * @default null
 
287
 * @type Object
 
288
 */
 
289
ATTRS[STRINGS] = {
 
290
    value: {},
 
291
    setter: "_strSetter",
 
292
    getter: "_strGetter"
 
293
};
 
294
 
 
295
/**
 
296
 * Whether or not to render the widget automatically after init, and optionally, to which parent node.
 
297
 *
 
298
 * @attribute render
 
299
 * @type boolean | Node
 
300
 * @writeOnce
 
301
 */
 
302
ATTRS[RENDER] = {
 
303
    value:FALSE,
 
304
    writeOnce:TRUE
 
305
};
 
306
 
 
307
/**
 
308
 * The css prefix which the static Widget.getClassName method should use when constructing class names
 
309
 *
 
310
 * @property CSS_PREFIX
 
311
 * @type String
 
312
 * @default Widget.NAME.toLowerCase()
 
313
 * @private
 
314
 * @static
 
315
 */
 
316
Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase());
 
317
 
 
318
/**
 
319
 * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined
 
320
 * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and
 
321
 * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for
 
322
 * the prefix and widget class name).
 
323
 * <p>
 
324
 * The instance based version of this method can be used to generate standard prefixed classnames,
 
325
 * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you
 
326
 * need to use a constant class name across different types instances.
 
327
 * </p>
 
328
 * @method getClassName
 
329
 * @param {String*} args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name
 
330
 */
 
331
Widget.getClassName = function() {
 
332
    // arguments needs to be array'fied to concat
 
333
    return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true));
 
334
};
 
335
 
 
336
_getWidgetClassName = Widget.getClassName;
 
337
 
 
338
/**
 
339
 * Returns the widget instance whose bounding box contains, or is, the given node.
 
340
 * <p>
 
341
 * In the case of nested widgets, the nearest bounding box ancestor is used to
 
342
 * return the widget instance.
 
343
 * </p>
 
344
 * @method getByNode
 
345
 * @static
 
346
 * @param node {Node | String} The node for which to return a Widget instance. If a selector
 
347
 * string is passed in, which selects more than one node, the first node found is used.
 
348
 * @return {Widget} Widget instance, or null if not found.
 
349
 */
 
350
Widget.getByNode = function(node) {
 
351
    var widget,
 
352
        widgetMarker = _getWidgetClassName();
 
353
 
 
354
    node = Node.one(node);
 
355
    if (node) {
 
356
        node = node.ancestor("." + widgetMarker, true);
 
357
        if (node) {
 
358
            widget = _instances[Y.stamp(node, true)];
 
359
        }
 
360
    }
 
361
 
 
362
    return widget || null;
 
363
};
 
364
 
 
365
Y.extend(Widget, Y.Base, {
 
366
 
 
367
    /**
 
368
     * Returns a class name prefixed with the the value of the
 
369
     * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property.
 
370
     * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings.
 
371
     * e.g.
 
372
     * <code>
 
373
     * <pre>
 
374
     *    // returns "yui-slider-foo-bar", for a slider instance
 
375
     *    var scn = slider.getClassName('foo','bar');
 
376
     *
 
377
     *    // returns "yui-overlay-foo-bar", for an overlay instance
 
378
     *    var ocn = overlay.getClassName('foo','bar');
 
379
     * </pre>
 
380
     * </code>
 
381
     *
 
382
     * @method getClassName
 
383
     * @param {String}+ One or more classname bits to be joined and prefixed
 
384
     */
 
385
    getClassName: function () {
 
386
        return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true));
 
387
    },
 
388
 
 
389
    /**
 
390
     * Initializer lifecycle implementation for the Widget class. Registers the
 
391
     * widget instance, and runs through the Widget's HTML_PARSER definition.
 
392
     *
 
393
     * @method initializer
 
394
     * @protected
 
395
     * @param  config {Object} Configuration object literal for the widget
 
396
     */
 
397
    initializer: function(config) {
 
398
        Y.log('initializer called', 'life', 'widget');
 
399
 
 
400
        var bb = this.get(BOUNDING_BOX);
 
401
 
 
402
        if (bb instanceof Node) {
 
403
            this._mapInstance(Y.stamp(bb));
 
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
        _instances[id] = this;
 
434
    },
 
435
 
 
436
    /**
 
437
     * Destructor lifecycle implementation for the Widget class. Purges events attached
 
438
     * to the bounding box and content box, removes them from the DOM and removes
 
439
     * the Widget from the list of registered widgets.
 
440
     *
 
441
     * @method destructor
 
442
     * @protected
 
443
     */
 
444
    destructor: function() {
 
445
        Y.log('destructor called', 'life', 'widget');
 
446
 
 
447
        var boundingBox = this.get(BOUNDING_BOX),
 
448
            bbGuid;
 
449
 
 
450
        if (boundingBox instanceof Node) {
 
451
            bbGuid = Y.stamp(boundingBox,true);
 
452
 
 
453
            if (bbGuid in _instances) {
 
454
                delete _instances[bbGuid];
 
455
            }
 
456
 
 
457
            this._destroyBox();
 
458
        }
 
459
    },
 
460
 
 
461
    /**
 
462
     * <p>
 
463
     * Destroy lifecycle method. Fires the destroy
 
464
     * event, prior to invoking destructors for the
 
465
     * class hierarchy.
 
466
     *
 
467
     * Overrides Base's implementation, to support arguments to destroy
 
468
     * </p>
 
469
     * <p>
 
470
     * Subscribers to the destroy
 
471
     * event can invoke preventDefault on the event object, to prevent destruction
 
472
     * from proceeding.
 
473
     * </p>
 
474
     * @method destroy
 
475
     * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are
 
476
     * removed and destroyed. Defaults to false due to potentially high run-time cost.
 
477
     * @return {Widget} A reference to this object
 
478
     * @chainable
 
479
     */
 
480
    destroy: function(destroyAllNodes) {
 
481
        this._destroyAllNodes = destroyAllNodes;
 
482
        return Widget.superclass.destroy.apply(this);
 
483
    },
 
484
 
 
485
    /**
 
486
     * Removes and destroys the widgets rendered boundingBox, contentBox,
 
487
     * and detaches bound UI events.
 
488
     *
 
489
     * @method _destroyBox
 
490
     * @protected
 
491
     */
 
492
    _destroyBox : function() {
 
493
 
 
494
        var boundingBox = this.get(BOUNDING_BOX),
 
495
            contentBox = this.get(CONTENT_BOX),
 
496
            deep = this._destroyAllNodes,
 
497
            same;
 
498
 
 
499
        same = boundingBox && boundingBox.compareTo(contentBox);
 
500
 
 
501
        if (this.UI_EVENTS) {
 
502
            this._destroyUIEvents();
 
503
        }
 
504
 
 
505
        this._unbindUI(boundingBox);
 
506
 
 
507
        if (contentBox) {
 
508
            if (deep) {
 
509
                contentBox.empty();
 
510
            }
 
511
            contentBox.remove(TRUE);
 
512
        }
 
513
 
 
514
        if (!same) {
 
515
            if (deep) {
 
516
                boundingBox.empty();
 
517
            }
 
518
            boundingBox.remove(TRUE);
 
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 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, true);
 
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, false);
 
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
     * @param {boolean} true if this is the boundingBox, false if it's the contentBox
 
813
     * @return {Node} The node
 
814
     */
 
815
    _setBox : function(id, node, template, isBounding) {
 
816
 
 
817
        node = Node.one(node);
 
818
 
 
819
        if (!node) {
 
820
            node = Node.create(template);
 
821
 
 
822
            if (isBounding) {
 
823
                this._bbFromTemplate = true;
 
824
            } else {
 
825
                this._cbFromTemplate = true;
 
826
            }
 
827
        }
 
828
 
 
829
        if (!node.get(ID)) {
 
830
            node.set(ID, id || Y.guid());
 
831
        }
 
832
 
 
833
        return node;
 
834
    },
 
835
 
 
836
    /**
 
837
     * Initializes the UI state for the Widget's bounding/content boxes.
 
838
     *
 
839
     * @method _renderUI
 
840
     * @protected
 
841
     */
 
842
    _renderUI: function() {
 
843
        this._renderBoxClassNames();
 
844
        this._renderBox(this._parentNode);
 
845
    },
 
846
 
 
847
    /**
 
848
     * Applies standard class names to the boundingBox and contentBox
 
849
     *
 
850
     * @method _renderBoxClassNames
 
851
     * @protected
 
852
     */
 
853
    _renderBoxClassNames : function() {
 
854
        var classes = this._getClasses(),
 
855
            cl,
 
856
            boundingBox = this.get(BOUNDING_BOX),
 
857
            i;
 
858
 
 
859
        boundingBox.addClass(_getWidgetClassName());
 
860
 
 
861
        // Start from Widget Sub Class
 
862
        for (i = classes.length-3; i >= 0; i--) {
 
863
            cl = classes[i];
 
864
            boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase()));
 
865
        }
 
866
 
 
867
        // Use instance based name for content box
 
868
        this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT));
 
869
    },
 
870
 
 
871
    /**
 
872
     * Removes class names representative of the widget's loading state from
 
873
     * the boundingBox.
 
874
     *
 
875
     * @method _removeLoadingClassNames
 
876
     * @protected
 
877
     */
 
878
    _removeLoadingClassNames: function () {
 
879
 
 
880
        var boundingBox = this.get(BOUNDING_BOX),
 
881
            contentBox = this.get(CONTENT_BOX),
 
882
            instClass = this.getClassName(LOADING),
 
883
            widgetClass = _getWidgetClassName(LOADING);
 
884
 
 
885
        boundingBox.removeClass(widgetClass)
 
886
                   .removeClass(instClass);
 
887
 
 
888
        contentBox.removeClass(widgetClass)
 
889
                  .removeClass(instClass);
 
890
    },
 
891
 
 
892
    /**
 
893
     * Sets up DOM and CustomEvent listeners for the widget.
 
894
     *
 
895
     * @method _bindUI
 
896
     * @protected
 
897
     */
 
898
    _bindUI: function() {
 
899
        this._bindAttrUI(this._UI_ATTRS.BIND);
 
900
        this._bindDOM();
 
901
    },
 
902
 
 
903
    /**
 
904
     * @method _unbindUI
 
905
     * @protected
 
906
     */
 
907
    _unbindUI : function(boundingBox) {
 
908
        this._unbindDOM(boundingBox);
 
909
    },
 
910
 
 
911
    /**
 
912
     * Sets up DOM listeners, on elements rendered by the widget.
 
913
     *
 
914
     * @method _bindDOM
 
915
     * @protected
 
916
     */
 
917
    _bindDOM : function() {
 
918
        var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT),
 
919
            focusHandle = Widget._hDocFocus;
 
920
 
 
921
        // Shared listener across all Widgets.
 
922
        if (!focusHandle) {
 
923
            focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this);
 
924
            focusHandle.listeners = {
 
925
                count: 0
 
926
            };
 
927
        }
 
928
 
 
929
        focusHandle.listeners[Y.stamp(this, true)] = true;
 
930
        focusHandle.listeners.count++;
 
931
 
 
932
        //      Fix for Webkit:
 
933
        //      Document doesn't receive focus in Webkit when the user mouses
 
934
        //      down on it, so the "focused" attribute won't get set to the
 
935
        //      correct value. Keeping this instance based for now, potential better performance.
 
936
        //  Otherwise we'll end up looking up widgets from the DOM on every mousedown.
 
937
        if (WEBKIT){
 
938
            this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this);
 
939
        }
 
940
    },
 
941
 
 
942
    /**
 
943
     * @method _unbindDOM
 
944
     * @protected
 
945
     */
 
946
    _unbindDOM : function(boundingBox) {
 
947
 
 
948
        var focusHandle = Widget._hDocFocus,
 
949
            yuid = Y.stamp(this, true),
 
950
            focusListeners,
 
951
            mouseHandle = this._hDocMouseDown;
 
952
 
 
953
        if (focusHandle) {
 
954
 
 
955
            focusListeners = focusHandle.listeners;
 
956
 
 
957
            if (focusListeners[yuid]) {
 
958
                delete focusListeners[yuid];
 
959
                focusListeners.count--;
 
960
            }
 
961
 
 
962
            if (focusListeners.count === 0) {
 
963
                focusHandle.detach();
 
964
                Widget._hDocFocus = null;
 
965
            }
 
966
        }
 
967
 
 
968
        if (WEBKIT && mouseHandle) {
 
969
            mouseHandle.detach();
 
970
        }
 
971
    },
 
972
 
 
973
    /**
 
974
     * Updates the widget UI to reflect the attribute state.
 
975
     *
 
976
     * @method _syncUI
 
977
     * @protected
 
978
     */
 
979
    _syncUI: function() {
 
980
        this._syncAttrUI(this._UI_ATTRS.SYNC);
 
981
    },
 
982
 
 
983
    /**
 
984
     * Sets the height on the widget's bounding box element
 
985
     *
 
986
     * @method _uiSetHeight
 
987
     * @protected
 
988
     * @param {String | Number} val
 
989
     */
 
990
    _uiSetHeight: function(val) {
 
991
        this._uiSetDim(HEIGHT, val);
 
992
        this._uiSizeCB((val !== EMPTY_STR && val !== AUTO));
 
993
    },
 
994
 
 
995
    /**
 
996
     * Sets the width on the widget's bounding box element
 
997
     *
 
998
     * @method _uiSetWidth
 
999
     * @protected
 
1000
     * @param {String | Number} val
 
1001
     */
 
1002
    _uiSetWidth: function(val) {
 
1003
        this._uiSetDim(WIDTH, val);
 
1004
    },
 
1005
 
 
1006
    /**
 
1007
     * @method _uiSetDim
 
1008
     * @private
 
1009
     * @param {String} dim The dimension - "width" or "height"
 
1010
     * @param {Number | String} val The value to set
 
1011
     */
 
1012
    _uiSetDim: function(dimension, val) {
 
1013
        this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val);
 
1014
    },
 
1015
 
 
1016
    /**
 
1017
     * Sets the visible state for the UI
 
1018
     *
 
1019
     * @method _uiSetVisible
 
1020
     * @protected
 
1021
     * @param {boolean} val
 
1022
     */
 
1023
    _uiSetVisible: function(val) {
 
1024
        this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val);
 
1025
    },
 
1026
 
 
1027
    /**
 
1028
     * Sets the disabled state for the UI
 
1029
     *
 
1030
     * @method _uiSetDisabled
 
1031
     * @protected
 
1032
     * @param {boolean} val
 
1033
     */
 
1034
    _uiSetDisabled: function(val) {
 
1035
        this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val);
 
1036
    },
 
1037
 
 
1038
    /**
 
1039
     * Sets the focused state for the UI
 
1040
     *
 
1041
     * @method _uiSetFocused
 
1042
     * @protected
 
1043
     * @param {boolean} val
 
1044
     * @param {string} src String representing the source that triggered an update to
 
1045
     * the UI.
 
1046
     */
 
1047
    _uiSetFocused: function(val, src) {
 
1048
         var boundingBox = this.get(BOUNDING_BOX);
 
1049
         boundingBox.toggleClass(this.getClassName(FOCUSED), val);
 
1050
 
 
1051
         if (src !== UI) {
 
1052
            if (val) {
 
1053
                boundingBox.focus();
 
1054
            } else {
 
1055
                boundingBox.blur();
 
1056
            }
 
1057
         }
 
1058
    },
 
1059
 
 
1060
    /**
 
1061
     * Set the tabIndex on the widget's rendered UI
 
1062
     *
 
1063
     * @method _uiSetTabIndex
 
1064
     * @protected
 
1065
     * @param Number
 
1066
     */
 
1067
    _uiSetTabIndex: function(index) {
 
1068
        var boundingBox = this.get(BOUNDING_BOX);
 
1069
 
 
1070
        if (L.isNumber(index)) {
 
1071
            boundingBox.set(TAB_INDEX, index);
 
1072
        } else {
 
1073
            boundingBox.removeAttribute(TAB_INDEX);
 
1074
        }
 
1075
    },
 
1076
 
 
1077
    /**
 
1078
     * @method _onDocMouseDown
 
1079
     * @description "mousedown" event handler for the owner document of the
 
1080
     * widget's bounding box.
 
1081
     * @protected
 
1082
     * @param {EventFacade} evt The event facade for the DOM focus event
 
1083
     */
 
1084
    _onDocMouseDown: function (evt) {
 
1085
        if (this._domFocus) {
 
1086
            this._onDocFocus(evt);
 
1087
        }
 
1088
    },
 
1089
 
 
1090
    /**
 
1091
     * DOM focus event handler, used to sync the state of the Widget with the DOM
 
1092
     *
 
1093
     * @method _onDocFocus
 
1094
     * @protected
 
1095
     * @param {EventFacade} evt The event facade for the DOM focus event
 
1096
     */
 
1097
    _onDocFocus: function (evt) {
 
1098
        var widget = Widget.getByNode(evt.target),
 
1099
            activeWidget = Widget._active;
 
1100
 
 
1101
        if (activeWidget && (activeWidget !== widget)) {
 
1102
            activeWidget._domFocus = false;
 
1103
            activeWidget._set(FOCUSED, false, {src:UI});
 
1104
 
 
1105
            Widget._active = null;
 
1106
        }
 
1107
 
 
1108
        if (widget) {
 
1109
            widget._domFocus = true;
 
1110
            widget._set(FOCUSED, true, {src:UI});
 
1111
 
 
1112
            Widget._active = widget;
 
1113
        }
 
1114
    },
 
1115
 
 
1116
    /**
 
1117
     * Generic toString implementation for all widgets.
 
1118
     *
 
1119
     * @method toString
 
1120
     * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ]
 
1121
     */
 
1122
    toString: function() {
 
1123
        // Using deprecated name prop for kweight squeeze.
 
1124
        return this.name + "[" + this.get(ID) + "]";
 
1125
    },
 
1126
 
 
1127
    /**
 
1128
     * Default unit to use for dimension values
 
1129
     *
 
1130
     * @property DEF_UNIT
 
1131
     * @type String
 
1132
     */
 
1133
    DEF_UNIT : "px",
 
1134
 
 
1135
    /**
 
1136
     * Default node to render the bounding box to. If not set,
 
1137
     * will default to the current document body.
 
1138
     *
 
1139
     * @property DEF_PARENT_NODE
 
1140
     * @type String | Node
 
1141
     */
 
1142
    DEF_PARENT_NODE : null,
 
1143
 
 
1144
    /**
 
1145
     * Property defining the markup template for content box. If your Widget doesn't
 
1146
     * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null,
 
1147
     * and contentBox and boundingBox will both point to the same Node.
 
1148
     *
 
1149
     * @property CONTENT_TEMPLATE
 
1150
     * @type String
 
1151
     */
 
1152
    CONTENT_TEMPLATE : DIV,
 
1153
 
 
1154
    /**
 
1155
     * Property defining the markup template for bounding box.
 
1156
     *
 
1157
     * @property BOUNDING_TEMPLATE
 
1158
     * @type String
 
1159
     */
 
1160
    BOUNDING_TEMPLATE : DIV,
 
1161
 
 
1162
    /**
 
1163
     * @method _guid
 
1164
     * @protected
 
1165
     */
 
1166
    _guid : function() {
 
1167
        return Y.guid();
 
1168
    },
 
1169
 
 
1170
    /**
 
1171
     * @method _validTabIndex
 
1172
     * @protected
 
1173
     * @param {Number} tabIndex
 
1174
     */
 
1175
    _validTabIndex : function (tabIndex) {
 
1176
        return (L.isNumber(tabIndex) || L.isNull(tabIndex));
 
1177
    },
 
1178
 
 
1179
    /**
 
1180
     * Binds after listeners for the list of attributes provided
 
1181
     *
 
1182
     * @method _bindAttrUI
 
1183
     * @private
 
1184
     * @param {Array} attrs
 
1185
     */
 
1186
    _bindAttrUI : function(attrs) {
 
1187
        var i,
 
1188
            l = attrs.length;
 
1189
 
 
1190
        for (i = 0; i < l; i++) {
 
1191
            this.after(attrs[i] + CHANGE, this._setAttrUI);
 
1192
        }
 
1193
    },
 
1194
 
 
1195
    /**
 
1196
     * Invokes the _uiSet&#61;ATTR NAME&#62; method for the list of attributes provided
 
1197
     *
 
1198
     * @method _syncAttrUI
 
1199
     * @private
 
1200
     * @param {Array} attrs
 
1201
     */
 
1202
    _syncAttrUI : function(attrs) {
 
1203
        var i, l = attrs.length, attr;
 
1204
        for (i = 0; i < l; i++) {
 
1205
            attr = attrs[i];
 
1206
            this[_UISET + _toInitialCap(attr)](this.get(attr));
 
1207
        }
 
1208
    },
 
1209
 
 
1210
    /**
 
1211
     * @method _setAttrUI
 
1212
     * @private
 
1213
     * @param {EventFacade} e
 
1214
     */
 
1215
    _setAttrUI : function(e) {
 
1216
        if (e.target === this) {
 
1217
            this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src);
 
1218
        }
 
1219
    },
 
1220
 
 
1221
    /**
 
1222
     * The default setter for the strings attribute. Merges partial sets
 
1223
     * into the full string set, to allow users to partial sets of strings
 
1224
     *
 
1225
     * @method _strSetter
 
1226
     * @protected
 
1227
     * @param {Object} strings
 
1228
     * @return {String} The full set of strings to set
 
1229
     */
 
1230
    _strSetter : function(strings) {
 
1231
        return Y.merge(this.get(STRINGS), strings);
 
1232
    },
 
1233
 
 
1234
    /**
 
1235
     * Helper method to get a specific string value
 
1236
     *
 
1237
     * @deprecated Used by deprecated WidgetLocale implementations.
 
1238
     * @method getString
 
1239
     * @param {String} key
 
1240
     * @return {String} The string
 
1241
     */
 
1242
    getString : function(key) {
 
1243
        return this.get(STRINGS)[key];
 
1244
    },
 
1245
 
 
1246
    /**
 
1247
     * Helper method to get the complete set of strings for the widget
 
1248
     *
 
1249
     * @deprecated  Used by deprecated WidgetLocale implementations.
 
1250
     * @method getStrings
 
1251
     * @param {String} key
 
1252
     * @return {String} The strings
 
1253
     */
 
1254
    getStrings : function() {
 
1255
        return this.get(STRINGS);
 
1256
    },
 
1257
 
 
1258
    /**
 
1259
     * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations
 
1260
     *
 
1261
     * @property _UI_ATTRS
 
1262
     * @type Object
 
1263
     * @private
 
1264
     */
 
1265
    _UI_ATTRS : {
 
1266
        BIND: UI_ATTRS,
 
1267
        SYNC: UI_ATTRS
 
1268
    }
 
1269
});
 
1270
 
 
1271
Y.Widget = Widget;
 
1272
 
 
1273
 
 
1274
}, '3.10.3', {
 
1275
    "requires": [
 
1276
        "attribute",
 
1277
        "base-base",
 
1278
        "base-pluginhost",
 
1279
        "classnamemanager",
 
1280
        "event-focus",
 
1281
        "node-base",
 
1282
        "node-style"
 
1283
    ],
 
1284
    "skinnable": true
 
1285
});