src/cm/media/js/lib/yui/yui_3.10.3/build/widget-buttons/widget-buttons.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-buttons', function (Y, NAME) {
       
     9 
       
    10 /**
       
    11 Provides header/body/footer button support for Widgets that use the
       
    12 `WidgetStdMod` extension.
       
    13 
       
    14 @module widget-buttons
       
    15 @since 3.4.0
       
    16 **/
       
    17 
       
    18 var YArray  = Y.Array,
       
    19     YLang   = Y.Lang,
       
    20     YObject = Y.Object,
       
    21 
       
    22     ButtonPlugin = Y.Plugin.Button,
       
    23     Widget       = Y.Widget,
       
    24     WidgetStdMod = Y.WidgetStdMod,
       
    25 
       
    26     getClassName = Y.ClassNameManager.getClassName,
       
    27     isArray      = YLang.isArray,
       
    28     isNumber     = YLang.isNumber,
       
    29     isString     = YLang.isString,
       
    30     isValue      = YLang.isValue;
       
    31 
       
    32 // Utility to determine if an object is a Y.Node instance, even if it was
       
    33 // created in a different YUI sandbox.
       
    34 function isNode(node) {
       
    35     return !!node.getDOMNode;
       
    36 }
       
    37 
       
    38 /**
       
    39 Provides header/body/footer button support for Widgets that use the
       
    40 `WidgetStdMod` extension.
       
    41 
       
    42 This Widget extension makes it easy to declaratively configure a widget's
       
    43 buttons. It adds a `buttons` attribute along with button- accessor and mutator
       
    44 methods. All button nodes have the `Y.Plugin.Button` plugin applied.
       
    45 
       
    46 This extension also includes `HTML_PARSER` support to seed a widget's `buttons`
       
    47 from those which already exist in its DOM.
       
    48 
       
    49 @class WidgetButtons
       
    50 @extensionfor Widget
       
    51 @since 3.4.0
       
    52 **/
       
    53 function WidgetButtons() {
       
    54     // Require `Y.WidgetStdMod`.
       
    55     if (!this._stdModNode) {
       
    56         Y.error('WidgetStdMod must be added to a Widget before WidgetButtons.');
       
    57     }
       
    58 
       
    59     // Has to be setup before the `initializer()`.
       
    60     this._buttonsHandles = {};
       
    61 }
       
    62 
       
    63 WidgetButtons.ATTRS = {
       
    64     /**
       
    65     Collection containing a widget's buttons.
       
    66 
       
    67     The collection is an Object which contains an Array of `Y.Node`s for every
       
    68     `WidgetStdMod` section (header, body, footer) which has one or more buttons.
       
    69     All button nodes have the `Y.Plugin.Button` plugin applied.
       
    70 
       
    71     This attribute is very flexible in the values it will accept. `buttons` can
       
    72     be specified as a single Array, or an Object of Arrays keyed to a particular
       
    73     section.
       
    74 
       
    75     All specified values will be normalized to this type of structure:
       
    76 
       
    77         {
       
    78             header: [...],
       
    79             footer: [...]
       
    80         }
       
    81 
       
    82     A button can be specified as a `Y.Node`, config Object, or String name for a
       
    83     predefined button on the `BUTTONS` prototype property. When a config Object
       
    84     is provided, it will be merged with any defaults provided by a button with
       
    85     the same `name` defined on the `BUTTONS` property.
       
    86 
       
    87     See `addButton()` for the detailed list of configuration properties.
       
    88 
       
    89     For convenience, a widget's buttons will always persist and remain rendered
       
    90     after header/body/footer content updates. Buttons should be removed by
       
    91     updating this attribute or using the `removeButton()` method.
       
    92 
       
    93     @example
       
    94         {
       
    95             // Uses predefined "close" button by string name.
       
    96             header: ['close'],
       
    97 
       
    98             footer: [
       
    99                 {
       
   100                     name  : 'cancel',
       
   101                     label : 'Cancel',
       
   102                     action: 'hide'
       
   103                 },
       
   104 
       
   105                 {
       
   106                     name     : 'okay',
       
   107                     label    : 'Okay',
       
   108                     isDefault: true,
       
   109 
       
   110                     events: {
       
   111                         click: function (e) {
       
   112                             this.hide();
       
   113                         }
       
   114                     }
       
   115                 }
       
   116             ]
       
   117         }
       
   118 
       
   119     @attribute buttons
       
   120     @type Object
       
   121     @default {}
       
   122     @since 3.4.0
       
   123     **/
       
   124     buttons: {
       
   125         getter: '_getButtons',
       
   126         setter: '_setButtons',
       
   127         value : {}
       
   128     },
       
   129 
       
   130     /**
       
   131     The current default button as configured through this widget's `buttons`.
       
   132 
       
   133     A button can be configured as the default button in the following ways:
       
   134 
       
   135       * As a config Object with an `isDefault` property:
       
   136         `{label: 'Okay', isDefault: true}`.
       
   137 
       
   138       * As a Node with a `data-default` attribute:
       
   139         `<button data-default="true">Okay</button>`.
       
   140 
       
   141     This attribute is **read-only**; anytime there are changes to this widget's
       
   142     `buttons`, the `defaultButton` will be updated if needed.
       
   143 
       
   144     **Note:** If two or more buttons are configured to be the default button,
       
   145     the last one wins.
       
   146 
       
   147     @attribute defaultButton
       
   148     @type Node
       
   149     @default null
       
   150     @readOnly
       
   151     @since 3.5.0
       
   152     **/
       
   153     defaultButton: {
       
   154         readOnly: true,
       
   155         value   : null
       
   156     }
       
   157 };
       
   158 
       
   159 /**
       
   160 CSS classes used by `WidgetButtons`.
       
   161 
       
   162 @property CLASS_NAMES
       
   163 @type Object
       
   164 @static
       
   165 @since 3.5.0
       
   166 **/
       
   167 WidgetButtons.CLASS_NAMES = {
       
   168     button : getClassName('button'),
       
   169     buttons: Widget.getClassName('buttons'),
       
   170     primary: getClassName('button', 'primary')
       
   171 };
       
   172 
       
   173 WidgetButtons.HTML_PARSER = {
       
   174     buttons: function (srcNode) {
       
   175         return this._parseButtons(srcNode);
       
   176     }
       
   177 };
       
   178 
       
   179 /**
       
   180 The list of button configuration properties which are specific to
       
   181 `WidgetButtons` and should not be passed to `Y.Plugin.Button.createNode()`.
       
   182 
       
   183 @property NON_BUTTON_NODE_CFG
       
   184 @type Array
       
   185 @static
       
   186 @since 3.5.0
       
   187 **/
       
   188 WidgetButtons.NON_BUTTON_NODE_CFG = [
       
   189     'action', 'classNames', 'context', 'events', 'isDefault', 'section'
       
   190 ];
       
   191 
       
   192 WidgetButtons.prototype = {
       
   193     // -- Public Properties ----------------------------------------------------
       
   194 
       
   195     /**
       
   196     Collection of predefined buttons mapped by name -> config.
       
   197 
       
   198     These button configurations will serve as defaults for any button added to a
       
   199     widget's buttons which have the same `name`.
       
   200 
       
   201     See `addButton()` for a list of possible configuration values.
       
   202 
       
   203     @property BUTTONS
       
   204     @type Object
       
   205     @default {}
       
   206     @see addButton()
       
   207     @since 3.5.0
       
   208     **/
       
   209     BUTTONS: {},
       
   210 
       
   211     /**
       
   212     The HTML template to use when creating the node which wraps all buttons of a
       
   213     section. By default it will have the CSS class: "yui3-widget-buttons".
       
   214 
       
   215     @property BUTTONS_TEMPLATE
       
   216     @type String
       
   217     @default "<span />"
       
   218     @since 3.5.0
       
   219     **/
       
   220     BUTTONS_TEMPLATE: '<span />',
       
   221 
       
   222     /**
       
   223     The default section to render buttons in when no section is specified.
       
   224 
       
   225     @property DEFAULT_BUTTONS_SECTION
       
   226     @type String
       
   227     @default Y.WidgetStdMod.FOOTER
       
   228     @since 3.5.0
       
   229     **/
       
   230     DEFAULT_BUTTONS_SECTION: WidgetStdMod.FOOTER,
       
   231 
       
   232     // -- Protected Properties -------------------------------------------------
       
   233 
       
   234     /**
       
   235     A map of button node `_yuid` -> event-handle for all button nodes which were
       
   236     created by this widget.
       
   237 
       
   238     @property _buttonsHandles
       
   239     @type Object
       
   240     @protected
       
   241     @since 3.5.0
       
   242     **/
       
   243 
       
   244     /**
       
   245     A map of this widget's `buttons`, both name -> button and
       
   246     section:name -> button.
       
   247 
       
   248     @property _buttonsMap
       
   249     @type Object
       
   250     @protected
       
   251     @since 3.5.0
       
   252     **/
       
   253 
       
   254     /**
       
   255     Internal reference to this widget's default button.
       
   256 
       
   257     @property _defaultButton
       
   258     @type Node
       
   259     @protected
       
   260     @since 3.5.0
       
   261     **/
       
   262 
       
   263     // -- Lifecycle Methods ----------------------------------------------------
       
   264 
       
   265     initializer: function () {
       
   266         // Creates button mappings and sets the `defaultButton`.
       
   267         this._mapButtons(this.get('buttons'));
       
   268         this._updateDefaultButton();
       
   269 
       
   270         // Bound with `Y.bind()` to make more extensible.
       
   271         this.after({
       
   272             buttonsChange      : Y.bind('_afterButtonsChange', this),
       
   273             defaultButtonChange: Y.bind('_afterDefaultButtonChange', this)
       
   274         });
       
   275 
       
   276         Y.after(this._bindUIButtons, this, 'bindUI');
       
   277         Y.after(this._syncUIButtons, this, 'syncUI');
       
   278     },
       
   279 
       
   280     destructor: function () {
       
   281         // Detach all event subscriptions this widget added to its `buttons`.
       
   282         YObject.each(this._buttonsHandles, function (handle) {
       
   283             handle.detach();
       
   284         });
       
   285 
       
   286         delete this._buttonsHandles;
       
   287         delete this._buttonsMap;
       
   288         delete this._defaultButton;
       
   289     },
       
   290 
       
   291     // -- Public Methods -------------------------------------------------------
       
   292 
       
   293     /**
       
   294     Adds a button to this widget.
       
   295 
       
   296     The new button node will have the `Y.Plugin.Button` plugin applied, be added
       
   297     to this widget's `buttons`, and rendered in the specified `section` at the
       
   298     specified `index` (or end of the section when no `index` is provided). If
       
   299     the section does not exist, it will be created.
       
   300 
       
   301     This fires the `buttonsChange` event and adds the following properties to
       
   302     the event facade:
       
   303 
       
   304       * `button`: The button node or config object to add.
       
   305 
       
   306       * `section`: The `WidgetStdMod` section (header/body/footer) where the
       
   307         button will be added.
       
   308 
       
   309       * `index`: The index at which the button will be in the section.
       
   310 
       
   311       * `src`: "add"
       
   312 
       
   313     **Note:** The `index` argument will be passed to the Array `splice()`
       
   314     method, therefore a negative value will insert the `button` that many items
       
   315     from the end. The `index` property on the `buttonsChange` event facade is
       
   316     the index at which the `button` was added.
       
   317 
       
   318     @method addButton
       
   319     @param {Node|Object|String} button The button to add. This can be a `Y.Node`
       
   320         instance, config Object, or String name for a predefined button on the
       
   321         `BUTTONS` prototype property. When a config Object is provided, it will
       
   322         be merged with any defaults provided by any `srcNode` and/or a button
       
   323         with the same `name` defined on the `BUTTONS` property. The following
       
   324         are the possible configuration properties beyond what Node plugins
       
   325         accept by default:
       
   326       @param {Function|String} [button.action] The default handler that should
       
   327         be called when the button is clicked. A String name of a Function that
       
   328         exists on the `context` object can also be provided. **Note:**
       
   329         Specifying a set of `events` will override this setting.
       
   330       @param {String|String[]} [button.classNames] Additional CSS classes to add
       
   331         to the button node.
       
   332       @param {Object} [button.context=this] Context which any `events` or
       
   333         `action` should be called with. Defaults to `this`, the widget.
       
   334         **Note:** `e.target` will access the button node in the event handlers.
       
   335       @param {Boolean} [button.disabled=false] Whether the button should be
       
   336         disabled.
       
   337       @param {String|Object} [button.events="click"] Event name, or set of
       
   338         events and handlers to bind to the button node. **See:** `Y.Node.on()`,
       
   339         this value is passed as the first argument to `on()`.
       
   340       @param {Boolean} [button.isDefault=false] Whether the button is the
       
   341         default button.
       
   342       @param {String} [button.label] The visible text/value displayed in the
       
   343         button.
       
   344       @param {String} [button.name] A name which can later be used to reference
       
   345         this button. If a button is defined on the `BUTTONS` property with this
       
   346         same name, its configuration properties will be merged in as defaults.
       
   347       @param {String} [button.section] The `WidgetStdMod` section (header, body,
       
   348         footer) where the button should be added.
       
   349       @param {Node} [button.srcNode] An existing Node to use for the button,
       
   350         default values will be seeded from this node, but are overriden by any
       
   351         values specified in the config object. By default a new &lt;button&gt;
       
   352         node will be created.
       
   353       @param {String} [button.template] A specific template to use when creating
       
   354         a new button node (e.g. "&lt;a /&gt;"). **Note:** Specifying a `srcNode`
       
   355         will overide this.
       
   356     @param {String} [section="footer"] The `WidgetStdMod` section
       
   357         (header/body/footer) where the button should be added. This takes
       
   358         precedence over the `button.section` configuration property.
       
   359     @param {Number} [index] The index at which the button should be inserted. If
       
   360         not specified, the button will be added to the end of the section. This
       
   361         value is passed to the Array `splice()` method, therefore a negative
       
   362         value will insert the `button` that many items from the end.
       
   363     @chainable
       
   364     @see Plugin.Button.createNode()
       
   365     @since 3.4.0
       
   366     **/
       
   367     addButton: function (button, section, index) {
       
   368         var buttons = this.get('buttons'),
       
   369             sectionButtons, atIndex;
       
   370 
       
   371         // Makes sure we have the full config object.
       
   372         if (!isNode(button)) {
       
   373             button = this._mergeButtonConfig(button);
       
   374             section || (section = button.section);
       
   375         }
       
   376 
       
   377         section || (section = this.DEFAULT_BUTTONS_SECTION);
       
   378         sectionButtons = buttons[section] || (buttons[section] = []);
       
   379         isNumber(index) || (index = sectionButtons.length);
       
   380 
       
   381         // Insert new button at the correct position.
       
   382         sectionButtons.splice(index, 0, button);
       
   383 
       
   384         // Determine the index at which the `button` now exists in the array.
       
   385         atIndex = YArray.indexOf(sectionButtons, button);
       
   386 
       
   387         this.set('buttons', buttons, {
       
   388             button : button,
       
   389             section: section,
       
   390             index  : atIndex,
       
   391             src    : 'add'
       
   392         });
       
   393 
       
   394         return this;
       
   395     },
       
   396 
       
   397     /**
       
   398     Returns a button node from this widget's `buttons`.
       
   399 
       
   400     @method getButton
       
   401     @param {Number|String} name The string name or index of the button.
       
   402     @param {String} [section="footer"] The `WidgetStdMod` section
       
   403         (header/body/footer) where the button exists. Only applicable when
       
   404         looking for a button by numerical index, or by name but scoped to a
       
   405         particular section.
       
   406     @return {Node} The button node.
       
   407     @since 3.5.0
       
   408     **/
       
   409     getButton: function (name, section) {
       
   410         if (!isValue(name)) { return; }
       
   411 
       
   412         var map = this._buttonsMap,
       
   413             buttons;
       
   414 
       
   415         section || (section = this.DEFAULT_BUTTONS_SECTION);
       
   416 
       
   417         // Supports `getButton(1, 'header')` signature.
       
   418         if (isNumber(name)) {
       
   419             buttons = this.get('buttons');
       
   420             return buttons[section] && buttons[section][name];
       
   421         }
       
   422 
       
   423         // Looks up button by name or section:name.
       
   424         return arguments.length > 1 ? map[section + ':' + name] : map[name];
       
   425     },
       
   426 
       
   427     /**
       
   428     Removes a button from this widget.
       
   429 
       
   430     The button will be removed from this widget's `buttons` and its DOM. Any
       
   431     event subscriptions on the button which were created by this widget will be
       
   432     detached. If the content section becomes empty after removing the button
       
   433     node, then the section will also be removed.
       
   434 
       
   435     This fires the `buttonsChange` event and adds the following properties to
       
   436     the event facade:
       
   437 
       
   438       * `button`: The button node to remove.
       
   439 
       
   440       * `section`: The `WidgetStdMod` section (header/body/footer) where the
       
   441         button should be removed from.
       
   442 
       
   443       * `index`: The index at which the button exists in the section.
       
   444 
       
   445       * `src`: "remove"
       
   446 
       
   447     @method removeButton
       
   448     @param {Node|Number|String} button The button to remove. This can be a
       
   449         `Y.Node` instance, index, or String name of a button.
       
   450     @param {String} [section="footer"] The `WidgetStdMod` section
       
   451         (header/body/footer) where the button exists. Only applicable when
       
   452         removing a button by numerical index, or by name but scoped to a
       
   453         particular section.
       
   454     @chainable
       
   455     @since 3.5.0
       
   456     **/
       
   457     removeButton: function (button, section) {
       
   458         if (!isValue(button)) { return this; }
       
   459 
       
   460         var buttons = this.get('buttons'),
       
   461             index;
       
   462 
       
   463         // Shortcut if `button` is already an index which is needed for slicing.
       
   464         if (isNumber(button)) {
       
   465             section || (section = this.DEFAULT_BUTTONS_SECTION);
       
   466             index  = button;
       
   467             button = buttons[section][index];
       
   468         } else {
       
   469             // Supports `button` being the string name.
       
   470             if (isString(button)) {
       
   471                 // `getButton()` is called this way because its behavior is
       
   472                 // different based on the number of arguments.
       
   473                 button = this.getButton.apply(this, arguments);
       
   474             }
       
   475 
       
   476             // Determines the `section` and `index` at which the button exists.
       
   477             YObject.some(buttons, function (sectionButtons, currentSection) {
       
   478                 index = YArray.indexOf(sectionButtons, button);
       
   479 
       
   480                 if (index > -1) {
       
   481                     section = currentSection;
       
   482                     return true;
       
   483                 }
       
   484             });
       
   485         }
       
   486 
       
   487         // Button was found at an appropriate index.
       
   488         if (button && index > -1) {
       
   489             // Remove button from `section` array.
       
   490             buttons[section].splice(index, 1);
       
   491 
       
   492             this.set('buttons', buttons, {
       
   493                 button : button,
       
   494                 section: section,
       
   495                 index  : index,
       
   496                 src    : 'remove'
       
   497             });
       
   498         }
       
   499 
       
   500         return this;
       
   501     },
       
   502 
       
   503     // -- Protected Methods ----------------------------------------------------
       
   504 
       
   505     /**
       
   506     Binds UI event listeners. This method is inserted via AOP, and will execute
       
   507     after `bindUI()`.
       
   508 
       
   509     @method _bindUIButtons
       
   510     @protected
       
   511     @since 3.4.0
       
   512     **/
       
   513     _bindUIButtons: function () {
       
   514         // Event handlers are bound with `bind()` to make them more extensible.
       
   515         var afterContentChange = Y.bind('_afterContentChangeButtons', this);
       
   516 
       
   517         this.after({
       
   518             visibleChange      : Y.bind('_afterVisibleChangeButtons', this),
       
   519             headerContentChange: afterContentChange,
       
   520             bodyContentChange  : afterContentChange,
       
   521             footerContentChange: afterContentChange
       
   522         });
       
   523     },
       
   524 
       
   525     /**
       
   526     Returns a button node based on the specified `button` node or configuration.
       
   527 
       
   528     The button node will either be created via `Y.Plugin.Button.createNode()`,
       
   529     or when `button` is specified as a node already, it will by `plug()`ed with
       
   530     `Y.Plugin.Button`.
       
   531 
       
   532     @method _createButton
       
   533     @param {Node|Object} button Button node or configuration object.
       
   534     @return {Node} The button node.
       
   535     @protected
       
   536     @since 3.5.0
       
   537     **/
       
   538     _createButton: function (button) {
       
   539         var config, buttonConfig, nonButtonNodeCfg,
       
   540             i, len, action, context, handle;
       
   541 
       
   542         // Makes sure the exiting `Y.Node` instance is from this YUI sandbox and
       
   543         // is plugged with `Y.Plugin.Button`.
       
   544         if (isNode(button)) {
       
   545             return Y.one(button.getDOMNode()).plug(ButtonPlugin);
       
   546         }
       
   547 
       
   548         // Merge `button` config with defaults and back-compat.
       
   549         config = Y.merge({
       
   550             context: this,
       
   551             events : 'click',
       
   552             label  : button.value
       
   553         }, button);
       
   554 
       
   555         buttonConfig     = Y.merge(config);
       
   556         nonButtonNodeCfg = WidgetButtons.NON_BUTTON_NODE_CFG;
       
   557 
       
   558         // Remove all non-button Node config props.
       
   559         for (i = 0, len = nonButtonNodeCfg.length; i < len; i += 1) {
       
   560             delete buttonConfig[nonButtonNodeCfg[i]];
       
   561         }
       
   562 
       
   563         // Create the button node using the button Node-only config.
       
   564         button = ButtonPlugin.createNode(buttonConfig);
       
   565 
       
   566         context = config.context;
       
   567         action  = config.action;
       
   568 
       
   569         // Supports `action` as a String name of a Function on the `context`
       
   570         // object.
       
   571         if (isString(action)) {
       
   572             action = Y.bind(action, context);
       
   573         }
       
   574 
       
   575         // Supports all types of crazy configs for event subscriptions and
       
   576         // stores a reference to the returned `EventHandle`.
       
   577         handle = button.on(config.events, action, context);
       
   578         this._buttonsHandles[Y.stamp(button, true)] = handle;
       
   579 
       
   580         // Tags the button with the configured `name` and `isDefault` settings.
       
   581         button.setData('name', this._getButtonName(config));
       
   582         button.setData('default', this._getButtonDefault(config));
       
   583 
       
   584         // Add any CSS classnames to the button node.
       
   585         YArray.each(YArray(config.classNames), button.addClass, button);
       
   586 
       
   587         return button;
       
   588     },
       
   589 
       
   590     /**
       
   591     Returns the buttons container for the specified `section`, passing a truthy
       
   592     value for `create` will create the node if it does not already exist.
       
   593 
       
   594     **Note:** It is up to the caller to properly insert the returned container
       
   595     node into the content section.
       
   596 
       
   597     @method _getButtonContainer
       
   598     @param {String} section The `WidgetStdMod` section (header/body/footer).
       
   599     @param {Boolean} create Whether the buttons container should be created if
       
   600         it does not already exist.
       
   601     @return {Node} The buttons container node for the specified `section`.
       
   602     @protected
       
   603     @see BUTTONS_TEMPLATE
       
   604     @since 3.5.0
       
   605     **/
       
   606     _getButtonContainer: function (section, create) {
       
   607         var sectionClassName = WidgetStdMod.SECTION_CLASS_NAMES[section],
       
   608             buttonsClassName = WidgetButtons.CLASS_NAMES.buttons,
       
   609             contentBox       = this.get('contentBox'),
       
   610             containerSelector, container;
       
   611 
       
   612         // Search for an existing buttons container within the section.
       
   613         containerSelector = '.' + sectionClassName + ' .' + buttonsClassName;
       
   614         container         = contentBox.one(containerSelector);
       
   615 
       
   616         // Create the `container` if it doesn't already exist.
       
   617         if (!container && create) {
       
   618             container = Y.Node.create(this.BUTTONS_TEMPLATE);
       
   619             container.addClass(buttonsClassName);
       
   620         }
       
   621 
       
   622         return container;
       
   623     },
       
   624 
       
   625     /**
       
   626     Returns whether or not the specified `button` is configured to be the
       
   627     default button.
       
   628 
       
   629     When a button node is specified, the button's `getData()` method will be
       
   630     used to determine if the button is configured to be the default. When a
       
   631     button config object is specified, the `isDefault` prop will determine
       
   632     whether the button is the default.
       
   633 
       
   634     **Note:** `<button data-default="true"></button>` is supported via the
       
   635     `button.getData('default')` API call.
       
   636 
       
   637     @method _getButtonDefault
       
   638     @param {Node|Object} button The button node or configuration object.
       
   639     @return {Boolean} Whether the button is configured to be the default button.
       
   640     @protected
       
   641     @since 3.5.0
       
   642     **/
       
   643     _getButtonDefault: function (button) {
       
   644         var isDefault = isNode(button) ?
       
   645                 button.getData('default') : button.isDefault;
       
   646 
       
   647         if (isString(isDefault)) {
       
   648             return isDefault.toLowerCase() === 'true';
       
   649         }
       
   650 
       
   651         return !!isDefault;
       
   652     },
       
   653 
       
   654     /**
       
   655     Returns the name of the specified `button`.
       
   656 
       
   657     When a button node is specified, the button's `getData('name')` method is
       
   658     preferred, but will fallback to `get('name')`, and the result will determine
       
   659     the button's name. When a button config object is specified, the `name` prop
       
   660     will determine the button's name.
       
   661 
       
   662     **Note:** `<button data-name="foo"></button>` is supported via the
       
   663     `button.getData('name')` API call.
       
   664 
       
   665     @method _getButtonName
       
   666     @param {Node|Object} button The button node or configuration object.
       
   667     @return {String} The name of the button.
       
   668     @protected
       
   669     @since 3.5.0
       
   670     **/
       
   671     _getButtonName: function (button) {
       
   672         var name;
       
   673 
       
   674         if (isNode(button)) {
       
   675             name = button.getData('name') || button.get('name');
       
   676         } else {
       
   677             name = button && (button.name || button.type);
       
   678         }
       
   679 
       
   680         return name;
       
   681     },
       
   682 
       
   683     /**
       
   684     Getter for the `buttons` attribute. A copy of the `buttons` object is
       
   685     returned so the stored state cannot be modified by the callers of
       
   686     `get('buttons')`.
       
   687 
       
   688     This will recreate a copy of the `buttons` object, and each section array
       
   689     (the button nodes are *not* copied/cloned.)
       
   690 
       
   691     @method _getButtons
       
   692     @param {Object} buttons The widget's current `buttons` state.
       
   693     @return {Object} A copy of the widget's current `buttons` state.
       
   694     @protected
       
   695     @since 3.5.0
       
   696     **/
       
   697     _getButtons: function (buttons) {
       
   698         var buttonsCopy = {};
       
   699 
       
   700         // Creates a new copy of the `buttons` object.
       
   701         YObject.each(buttons, function (sectionButtons, section) {
       
   702             // Creates of copy of the array of button nodes.
       
   703             buttonsCopy[section] = sectionButtons.concat();
       
   704         });
       
   705 
       
   706         return buttonsCopy;
       
   707     },
       
   708 
       
   709     /**
       
   710     Adds the specified `button` to the buttons map (both name -> button and
       
   711     section:name -> button), and sets the button as the default if it is
       
   712     configured as the default button.
       
   713 
       
   714     **Note:** If two or more buttons are configured with the same `name` and/or
       
   715     configured to be the default button, the last one wins.
       
   716 
       
   717     @method _mapButton
       
   718     @param {Node} button The button node to map.
       
   719     @param {String} section The `WidgetStdMod` section (header/body/footer).
       
   720     @protected
       
   721     @since 3.5.0
       
   722     **/
       
   723     _mapButton: function (button, section) {
       
   724         var map       = this._buttonsMap,
       
   725             name      = this._getButtonName(button),
       
   726             isDefault = this._getButtonDefault(button);
       
   727 
       
   728         if (name) {
       
   729             // name -> button
       
   730             map[name] = button;
       
   731 
       
   732             // section:name -> button
       
   733             map[section + ':' + name] = button;
       
   734         }
       
   735 
       
   736         isDefault && (this._defaultButton = button);
       
   737     },
       
   738 
       
   739     /**
       
   740     Adds the specified `buttons` to the buttons map (both name -> button and
       
   741     section:name -> button), and set the a button as the default if one is
       
   742     configured as the default button.
       
   743 
       
   744     **Note:** This will clear all previous button mappings and null-out any
       
   745     previous default button! If two or more buttons are configured with the same
       
   746     `name` and/or configured to be the default button, the last one wins.
       
   747 
       
   748     @method _mapButtons
       
   749     @param {Node[]} buttons The button nodes to map.
       
   750     @protected
       
   751     @since 3.5.0
       
   752     **/
       
   753     _mapButtons: function (buttons) {
       
   754         this._buttonsMap    = {};
       
   755         this._defaultButton = null;
       
   756 
       
   757         YObject.each(buttons, function (sectionButtons, section) {
       
   758             var i, len;
       
   759 
       
   760             for (i = 0, len = sectionButtons.length; i < len; i += 1) {
       
   761                 this._mapButton(sectionButtons[i], section);
       
   762             }
       
   763         }, this);
       
   764     },
       
   765 
       
   766     /**
       
   767     Returns a copy of the specified `config` object merged with any defaults
       
   768     provided by a `srcNode` and/or a predefined configuration for a button
       
   769     with the same `name` on the `BUTTONS` property.
       
   770 
       
   771     @method _mergeButtonConfig
       
   772     @param {Object|String} config Button configuration object, or string name.
       
   773     @return {Object} A copy of the button configuration object merged with any
       
   774         defaults.
       
   775     @protected
       
   776     @since 3.5.0
       
   777     **/
       
   778     _mergeButtonConfig: function (config) {
       
   779         var buttonConfig, defConfig, name, button, tagName, label;
       
   780 
       
   781         // Makes sure `config` is an Object and a copy of the specified value.
       
   782         config = isString(config) ? {name: config} : Y.merge(config);
       
   783 
       
   784         // Seeds default values from the button node, if there is one.
       
   785         if (config.srcNode) {
       
   786             button  = config.srcNode;
       
   787             tagName = button.get('tagName').toLowerCase();
       
   788             label   = button.get(tagName === 'input' ? 'value' : 'text');
       
   789 
       
   790             // Makes sure the button's current values override any defaults.
       
   791             buttonConfig = {
       
   792                 disabled : !!button.get('disabled'),
       
   793                 isDefault: this._getButtonDefault(button),
       
   794                 name     : this._getButtonName(button)
       
   795             };
       
   796 
       
   797             // Label should only be considered when not an empty string.
       
   798             label && (buttonConfig.label = label);
       
   799 
       
   800             // Merge `config` with `buttonConfig` values.
       
   801             Y.mix(config, buttonConfig, false, null, 0, true);
       
   802         }
       
   803 
       
   804         name      = this._getButtonName(config);
       
   805         defConfig = this.BUTTONS && this.BUTTONS[name];
       
   806 
       
   807         // Merge `config` with predefined default values.
       
   808         if (defConfig) {
       
   809             Y.mix(config, defConfig, false, null, 0, true);
       
   810         }
       
   811 
       
   812         return config;
       
   813     },
       
   814 
       
   815     /**
       
   816     `HTML_PARSER` implementation for the `buttons` attribute.
       
   817 
       
   818     **Note:** To determine a button node's name its `data-name` and `name`
       
   819     attributes are examined. Whether the button should be the default is
       
   820     determined by its `data-default` attribute.
       
   821 
       
   822     @method _parseButtons
       
   823     @param {Node} srcNode This widget's srcNode to search for buttons.
       
   824     @return {null|Object} `buttons` Config object parsed from this widget's DOM.
       
   825     @protected
       
   826     @since 3.5.0
       
   827     **/
       
   828     _parseButtons: function (srcNode) {
       
   829         var buttonSelector = '.' + WidgetButtons.CLASS_NAMES.button,
       
   830             sections       = ['header', 'body', 'footer'],
       
   831             buttonsConfig  = null;
       
   832 
       
   833         YArray.each(sections, function (section) {
       
   834             var container = this._getButtonContainer(section),
       
   835                 buttons   = container && container.all(buttonSelector),
       
   836                 sectionButtons;
       
   837 
       
   838             if (!buttons || buttons.isEmpty()) { return; }
       
   839 
       
   840             sectionButtons = [];
       
   841 
       
   842             // Creates a button config object for every button node found and
       
   843             // adds it to the section. This way each button configuration can be
       
   844             // merged with any defaults provided by predefined `BUTTONS`.
       
   845             buttons.each(function (button) {
       
   846                 sectionButtons.push({srcNode: button});
       
   847             });
       
   848 
       
   849             buttonsConfig || (buttonsConfig = {});
       
   850             buttonsConfig[section] = sectionButtons;
       
   851         }, this);
       
   852 
       
   853         return buttonsConfig;
       
   854     },
       
   855 
       
   856     /**
       
   857     Setter for the `buttons` attribute. This processes the specified `config`
       
   858     and returns a new `buttons` object which is stored as the new state; leaving
       
   859     the original, specified `config` unmodified.
       
   860 
       
   861     The button nodes will either be created via `Y.Plugin.Button.createNode()`,
       
   862     or when a button is already a Node already, it will by `plug()`ed with
       
   863     `Y.Plugin.Button`.
       
   864 
       
   865     @method _setButtons
       
   866     @param {Array|Object} config The `buttons` configuration to process.
       
   867     @return {Object} The processed `buttons` object which represents the new
       
   868         state.
       
   869     @protected
       
   870     @since 3.5.0
       
   871     **/
       
   872     _setButtons: function (config) {
       
   873         var defSection = this.DEFAULT_BUTTONS_SECTION,
       
   874             buttons    = {};
       
   875 
       
   876         function processButtons(buttonConfigs, currentSection) {
       
   877             if (!isArray(buttonConfigs)) { return; }
       
   878 
       
   879             var i, len, button, section;
       
   880 
       
   881             for (i = 0, len = buttonConfigs.length; i < len; i += 1) {
       
   882                 button  = buttonConfigs[i];
       
   883                 section = currentSection;
       
   884 
       
   885                 if (!isNode(button)) {
       
   886                     button = this._mergeButtonConfig(button);
       
   887                     section || (section = button.section);
       
   888                 }
       
   889 
       
   890                 // Always passes through `_createButton()` to make sure the node
       
   891                 // is decorated as a button.
       
   892                 button = this._createButton(button);
       
   893 
       
   894                 // Use provided `section` or fallback to the default section.
       
   895                 section || (section = defSection);
       
   896 
       
   897                 // Add button to the array of buttons for the specified section.
       
   898                 (buttons[section] || (buttons[section] = [])).push(button);
       
   899             }
       
   900         }
       
   901 
       
   902         // Handle `config` being either an Array or Object of Arrays.
       
   903         if (isArray(config)) {
       
   904             processButtons.call(this, config);
       
   905         } else {
       
   906             YObject.each(config, processButtons, this);
       
   907         }
       
   908 
       
   909         return buttons;
       
   910     },
       
   911 
       
   912     /**
       
   913     Syncs this widget's current button-related state to its DOM. This method is
       
   914     inserted via AOP, and will execute after `syncUI()`.
       
   915 
       
   916     @method _syncUIButtons
       
   917     @protected
       
   918     @since 3.4.0
       
   919     **/
       
   920     _syncUIButtons: function () {
       
   921         this._uiSetButtons(this.get('buttons'));
       
   922         this._uiSetDefaultButton(this.get('defaultButton'));
       
   923         this._uiSetVisibleButtons(this.get('visible'));
       
   924     },
       
   925 
       
   926     /**
       
   927     Inserts the specified `button` node into this widget's DOM at the specified
       
   928     `section` and `index` and updates the section content.
       
   929 
       
   930     The section and button container nodes will be created if they do not
       
   931     already exist.
       
   932 
       
   933     @method _uiInsertButton
       
   934     @param {Node} button The button node to insert into this widget's DOM.
       
   935     @param {String} section The `WidgetStdMod` section (header/body/footer).
       
   936     @param {Number} index Index at which the `button` should be positioned.
       
   937     @protected
       
   938     @since 3.5.0
       
   939     **/
       
   940     _uiInsertButton: function (button, section, index) {
       
   941         var buttonsClassName = WidgetButtons.CLASS_NAMES.button,
       
   942             buttonContainer  = this._getButtonContainer(section, true),
       
   943             sectionButtons   = buttonContainer.all('.' + buttonsClassName);
       
   944 
       
   945         // Inserts the button node at the correct index.
       
   946         buttonContainer.insertBefore(button, sectionButtons.item(index));
       
   947 
       
   948         // Adds the button container to the section content.
       
   949         this.setStdModContent(section, buttonContainer, 'after');
       
   950     },
       
   951 
       
   952     /**
       
   953     Removes the button node from this widget's DOM and detaches any event
       
   954     subscriptions on the button that were created by this widget. The section
       
   955     content will be updated unless `{preserveContent: true}` is passed in the
       
   956     `options`.
       
   957 
       
   958     By default the button container node will be removed when this removes the
       
   959     last button of the specified `section`; and if no other content remains in
       
   960     the section node, it will also be removed.
       
   961 
       
   962     @method _uiRemoveButton
       
   963     @param {Node} button The button to remove and destroy.
       
   964     @param {String} section The `WidgetStdMod` section (header/body/footer).
       
   965     @param {Object} [options] Additional options.
       
   966       @param {Boolean} [options.preserveContent=false] Whether the section
       
   967         content should be updated.
       
   968     @protected
       
   969     @since 3.5.0
       
   970     **/
       
   971     _uiRemoveButton: function (button, section, options) {
       
   972         var yuid    = Y.stamp(button, this),
       
   973             handles = this._buttonsHandles,
       
   974             handle  = handles[yuid],
       
   975             buttonContainer, buttonClassName;
       
   976 
       
   977         if (handle) {
       
   978             handle.detach();
       
   979         }
       
   980 
       
   981         delete handles[yuid];
       
   982 
       
   983         button.remove();
       
   984 
       
   985         options || (options = {});
       
   986 
       
   987         // Remove the button container and section nodes if needed.
       
   988         if (!options.preserveContent) {
       
   989             buttonContainer = this._getButtonContainer(section);
       
   990             buttonClassName = WidgetButtons.CLASS_NAMES.button;
       
   991 
       
   992             // Only matters if we have a button container which is empty.
       
   993             if (buttonContainer &&
       
   994                     buttonContainer.all('.' + buttonClassName).isEmpty()) {
       
   995 
       
   996                 buttonContainer.remove();
       
   997                 this._updateContentButtons(section);
       
   998             }
       
   999         }
       
  1000     },
       
  1001 
       
  1002     /**
       
  1003     Sets the current `buttons` state to this widget's DOM by rendering the
       
  1004     specified collection of `buttons` and updates the contents of each section
       
  1005     as needed.
       
  1006 
       
  1007     Button nodes which already exist in the DOM will remain intact, or will be
       
  1008     moved if they should be in a new position. Old button nodes which are no
       
  1009     longer represented in the specified `buttons` collection will be removed,
       
  1010     and any event subscriptions on the button which were created by this widget
       
  1011     will be detached.
       
  1012 
       
  1013     If the button nodes in this widget's DOM actually change, then each content
       
  1014     section will be updated (or removed) appropriately.
       
  1015 
       
  1016     @method _uiSetButtons
       
  1017     @param {Object} buttons The current `buttons` state to visually represent.
       
  1018     @protected
       
  1019     @since 3.5.0
       
  1020     **/
       
  1021     _uiSetButtons: function (buttons) {
       
  1022         var buttonClassName = WidgetButtons.CLASS_NAMES.button,
       
  1023             sections        = ['header', 'body', 'footer'];
       
  1024 
       
  1025         YArray.each(sections, function (section) {
       
  1026             var sectionButtons  = buttons[section] || [],
       
  1027                 numButtons      = sectionButtons.length,
       
  1028                 buttonContainer = this._getButtonContainer(section, numButtons),
       
  1029                 buttonsUpdated  = false,
       
  1030                 oldNodes, i, button, buttonIndex;
       
  1031 
       
  1032             // When there's no button container, there are no new buttons or old
       
  1033             // buttons that we have to deal with for this section.
       
  1034             if (!buttonContainer) { return; }
       
  1035 
       
  1036             oldNodes = buttonContainer.all('.' + buttonClassName);
       
  1037 
       
  1038             for (i = 0; i < numButtons; i += 1) {
       
  1039                 button      = sectionButtons[i];
       
  1040                 buttonIndex = oldNodes.indexOf(button);
       
  1041 
       
  1042                 // Buttons already rendered in the Widget should remain there or
       
  1043                 // moved to their new index. New buttons will be added to the
       
  1044                 // current `buttonContainer`.
       
  1045                 if (buttonIndex > -1) {
       
  1046                     // Remove button from existing buttons nodeList since its in
       
  1047                     // the DOM already.
       
  1048                     oldNodes.splice(buttonIndex, 1);
       
  1049 
       
  1050                     // Check that the button is at the right position, if not,
       
  1051                     // move it to its new position.
       
  1052                     if (buttonIndex !== i) {
       
  1053                         // Using `i + 1` because the button should be at index
       
  1054                         // `i`; it's inserted before the node which comes after.
       
  1055                         buttonContainer.insertBefore(button, i + 1);
       
  1056                         buttonsUpdated = true;
       
  1057                     }
       
  1058                 } else {
       
  1059                     buttonContainer.appendChild(button);
       
  1060                     buttonsUpdated = true;
       
  1061                 }
       
  1062             }
       
  1063 
       
  1064             // Safely removes the old button nodes which are no longer part of
       
  1065             // this widget's `buttons`.
       
  1066             oldNodes.each(function (button) {
       
  1067                 this._uiRemoveButton(button, section, {preserveContent: true});
       
  1068                 buttonsUpdated = true;
       
  1069             }, this);
       
  1070 
       
  1071             // Remove leftover empty button containers and updated the StdMod
       
  1072             // content area.
       
  1073             if (numButtons === 0) {
       
  1074                 buttonContainer.remove();
       
  1075                 this._updateContentButtons(section);
       
  1076                 return;
       
  1077             }
       
  1078 
       
  1079             // Adds the button container to the section content.
       
  1080             if (buttonsUpdated) {
       
  1081                 this.setStdModContent(section, buttonContainer, 'after');
       
  1082             }
       
  1083         }, this);
       
  1084     },
       
  1085 
       
  1086     /**
       
  1087     Adds the "yui3-button-primary" CSS class to the new `defaultButton` and
       
  1088     removes it from the old default button.
       
  1089 
       
  1090     @method _uiSetDefaultButton
       
  1091     @param {Node} newButton The new `defaultButton`.
       
  1092     @param {Node} oldButton The old `defaultButton`.
       
  1093     @protected
       
  1094     @since 3.5.0
       
  1095     **/
       
  1096     _uiSetDefaultButton: function (newButton, oldButton) {
       
  1097         var primaryClassName = WidgetButtons.CLASS_NAMES.primary;
       
  1098 
       
  1099         if (newButton) { newButton.addClass(primaryClassName); }
       
  1100         if (oldButton) { oldButton.removeClass(primaryClassName); }
       
  1101     },
       
  1102 
       
  1103     /**
       
  1104     Focuses this widget's `defaultButton` if there is one and this widget is
       
  1105     visible.
       
  1106 
       
  1107     @method _uiSetVisibleButtons
       
  1108     @param {Boolean} visible Whether this widget is visible.
       
  1109     @protected
       
  1110     @since 3.5.0
       
  1111     **/
       
  1112     _uiSetVisibleButtons: function (visible) {
       
  1113         if (!visible) { return; }
       
  1114 
       
  1115         var defaultButton = this.get('defaultButton');
       
  1116         if (defaultButton) {
       
  1117             defaultButton.focus();
       
  1118         }
       
  1119     },
       
  1120 
       
  1121     /**
       
  1122     Removes the specified `button` from the buttons map (both name -> button and
       
  1123     section:name -> button), and nulls-out the `defaultButton` if it is
       
  1124     currently the default button.
       
  1125 
       
  1126     @method _unMapButton
       
  1127     @param {Node} button The button node to remove from the buttons map.
       
  1128     @param {String} section The `WidgetStdMod` section (header/body/footer).
       
  1129     @protected
       
  1130     @since 3.5.0
       
  1131     **/
       
  1132     _unMapButton: function (button, section) {
       
  1133         var map  = this._buttonsMap,
       
  1134             name = this._getButtonName(button),
       
  1135             sectionName;
       
  1136 
       
  1137         // Only delete the map entry if the specified `button` is mapped to it.
       
  1138         if (name) {
       
  1139             // name -> button
       
  1140             if (map[name] === button) {
       
  1141                 delete map[name];
       
  1142             }
       
  1143 
       
  1144             // section:name -> button
       
  1145             sectionName = section + ':' + name;
       
  1146             if (map[sectionName] === button) {
       
  1147                 delete map[sectionName];
       
  1148             }
       
  1149         }
       
  1150 
       
  1151         // Clear the default button if its the specified `button`.
       
  1152         if (this._defaultButton === button) {
       
  1153             this._defaultButton = null;
       
  1154         }
       
  1155     },
       
  1156 
       
  1157     /**
       
  1158     Updates the `defaultButton` attribute if it needs to be updated by comparing
       
  1159     its current value with the protected `_defaultButton` property.
       
  1160 
       
  1161     @method _updateDefaultButton
       
  1162     @protected
       
  1163     @since 3.5.0
       
  1164     **/
       
  1165     _updateDefaultButton: function () {
       
  1166         var defaultButton = this._defaultButton;
       
  1167 
       
  1168         if (this.get('defaultButton') !== defaultButton) {
       
  1169             this._set('defaultButton', defaultButton);
       
  1170         }
       
  1171     },
       
  1172 
       
  1173     /**
       
  1174     Updates the content attribute which corresponds to the specified `section`.
       
  1175 
       
  1176     The method updates the section's content to its current `childNodes`
       
  1177     (text and/or HTMLElement), or will null-out its contents if the section is
       
  1178     empty. It also specifies a `src` of `buttons` on the change event facade.
       
  1179 
       
  1180     @method _updateContentButtons
       
  1181     @param {String} section The `WidgetStdMod` section (header/body/footer) to
       
  1182         update.
       
  1183     @protected
       
  1184     @since 3.5.0
       
  1185     **/
       
  1186     _updateContentButtons: function (section) {
       
  1187         // `childNodes` return text nodes and HTMLElements.
       
  1188         var sectionContent = this.getStdModNode(section).get('childNodes');
       
  1189 
       
  1190         // Updates the section to its current contents, or null if it is empty.
       
  1191         this.set(section + 'Content', sectionContent.isEmpty() ? null :
       
  1192             sectionContent, {src: 'buttons'});
       
  1193     },
       
  1194 
       
  1195     // -- Protected Event Handlers ---------------------------------------------
       
  1196 
       
  1197     /**
       
  1198     Handles this widget's `buttonsChange` event which fires anytime the
       
  1199     `buttons` attribute is modified.
       
  1200 
       
  1201     **Note:** This method special-cases the `buttons` modifications caused by
       
  1202     `addButton()` and `removeButton()`, both of which set the `src` property on
       
  1203     the event facade to "add" and "remove" respectively.
       
  1204 
       
  1205     @method _afterButtonsChange
       
  1206     @param {EventFacade} e
       
  1207     @protected
       
  1208     @since 3.4.0
       
  1209     **/
       
  1210     _afterButtonsChange: function (e) {
       
  1211         var buttons = e.newVal,
       
  1212             section = e.section,
       
  1213             index   = e.index,
       
  1214             src     = e.src,
       
  1215             button;
       
  1216 
       
  1217         // Special cases `addButton()` to only set and insert the new button.
       
  1218         if (src === 'add') {
       
  1219             // Make sure we have the button node.
       
  1220             button = buttons[section][index];
       
  1221 
       
  1222             this._mapButton(button, section);
       
  1223             this._updateDefaultButton();
       
  1224             this._uiInsertButton(button, section, index);
       
  1225 
       
  1226             return;
       
  1227         }
       
  1228 
       
  1229         // Special cases `removeButton()` to only remove the specified button.
       
  1230         if (src === 'remove') {
       
  1231             // Button node already exists on the event facade.
       
  1232             button = e.button;
       
  1233 
       
  1234             this._unMapButton(button, section);
       
  1235             this._updateDefaultButton();
       
  1236             this._uiRemoveButton(button, section);
       
  1237 
       
  1238             return;
       
  1239         }
       
  1240 
       
  1241         this._mapButtons(buttons);
       
  1242         this._updateDefaultButton();
       
  1243         this._uiSetButtons(buttons);
       
  1244     },
       
  1245 
       
  1246     /**
       
  1247     Handles this widget's `headerContentChange`, `bodyContentChange`,
       
  1248     `footerContentChange` events by making sure the `buttons` remain rendered
       
  1249     after changes to the content areas.
       
  1250 
       
  1251     These events are very chatty, so extra caution is taken to avoid doing extra
       
  1252     work or getting into an infinite loop.
       
  1253 
       
  1254     @method _afterContentChangeButtons
       
  1255     @param {EventFacade} e
       
  1256     @protected
       
  1257     @since 3.5.0
       
  1258     **/
       
  1259     _afterContentChangeButtons: function (e) {
       
  1260         var src     = e.src,
       
  1261             pos     = e.stdModPosition,
       
  1262             replace = !pos || pos === WidgetStdMod.REPLACE;
       
  1263 
       
  1264         // Only do work when absolutely necessary.
       
  1265         if (replace && src !== 'buttons' && src !== Widget.UI_SRC) {
       
  1266             this._uiSetButtons(this.get('buttons'));
       
  1267         }
       
  1268     },
       
  1269 
       
  1270     /**
       
  1271     Handles this widget's `defaultButtonChange` event by adding the
       
  1272     "yui3-button-primary" CSS class to the new `defaultButton` and removing it
       
  1273     from the old default button.
       
  1274 
       
  1275     @method _afterDefaultButtonChange
       
  1276     @param {EventFacade} e
       
  1277     @protected
       
  1278     @since 3.5.0
       
  1279     **/
       
  1280     _afterDefaultButtonChange: function (e) {
       
  1281         this._uiSetDefaultButton(e.newVal, e.prevVal);
       
  1282     },
       
  1283 
       
  1284     /**
       
  1285     Handles this widget's `visibleChange` event by focusing the `defaultButton`
       
  1286     if there is one.
       
  1287 
       
  1288     @method _afterVisibleChangeButtons
       
  1289     @param {EventFacade} e
       
  1290     @protected
       
  1291     @since 3.5.0
       
  1292     **/
       
  1293     _afterVisibleChangeButtons: function (e) {
       
  1294         this._uiSetVisibleButtons(e.newVal);
       
  1295     }
       
  1296 };
       
  1297 
       
  1298 Y.WidgetButtons = WidgetButtons;
       
  1299 
       
  1300 
       
  1301 }, '3.10.3', {"requires": ["button-plugin", "cssbutton", "widget-stdmod"]});