src/cm/media/js/lib/yui/yui_3.10.3/build/widget-base/widget-base-debug.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     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 });