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