2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
9 * @description <p>The Button Control enables the creation of rich, graphical
10 * buttons that function like traditional HTML form buttons. <em>Unlike</em>
11 * traditional HTML form buttons, buttons created with the Button Control can have
12 * a label that is different from its value. With the inclusion of the optional
13 * <a href="module_menu.html">Menu Control</a>, the Button Control can also be
14 * used to create menu buttons and split buttons, controls that are not
15 * available natively in HTML. The Button Control can also be thought of as a
16 * way to create more visually engaging implementations of the browser's
17 * default radio-button and check-box controls.</p>
18 * <p>The Button Control supports the following types:</p>
21 * <dd>Basic push button that can execute a user-specified command when
24 * <dd>Navigates to a specified url when pressed.</dd>
26 * <dd>Submits the parent form when pressed.</dd>
28 * <dd>Resets the parent form when pressed.</dd>
30 * <dd>Maintains a "checked" state that can be toggled on and off.</dd>
32 * <dd>Maintains a "checked" state that can be toggled on and off. Use with
33 * the ButtonGroup class to create a set of controls that are mutually
34 * exclusive; checking one button in the set will uncheck all others in
37 * <dd>When pressed will show/hide a menu.</dd>
39 * <dd>Can execute a user-specified command or display a menu when pressed.</dd>
42 * @namespace YAHOO.widget
43 * @requires yahoo, dom, element, event
44 * @optional container, menu
52 * The Button class creates a rich, graphical button.
53 * @param {String} p_oElement String specifying the id attribute of the
54 * <code><input></code>, <code><button></code>,
55 * <code><a></code>, or <code><span></code> element to
56 * be used to create the button.
57 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
58 * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org
59 * /TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-34812697">
60 * HTMLButtonElement</a>|<a href="
61 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
62 * ID-33759296">HTMLElement</a>} p_oElement Object reference for the
63 * <code><input></code>, <code><button></code>,
64 * <code><a></code>, or <code><span></code> element to be
65 * used to create the button.
66 * @param {Object} p_oElement Object literal specifying a set of
67 * configuration attributes used to create the button.
68 * @param {Object} p_oAttributes Optional. Object literal specifying a set
69 * of configuration attributes used to create the button.
70 * @namespace YAHOO.widget
73 * @extends YAHOO.util.Element
78 // Shorthard for utilities
80 var Dom = YAHOO.util.Dom,
81 Event = YAHOO.util.Event,
84 Overlay = YAHOO.widget.Overlay,
85 Menu = YAHOO.widget.Menu,
88 // Private member variables
90 m_oButtons = {}, // Collection of all Button instances
91 m_oOverlayManager = null, // YAHOO.widget.OverlayManager instance
92 m_oSubmitTrigger = null, // The button that submitted the form
93 m_oFocusedButton = null; // The button that has focus
102 * @method createInputElement
103 * @description Creates an <code><input></code> element of the
106 * @param {String} p_sType String specifying the type of
107 * <code><input></code> element to create.
108 * @param {String} p_sName String specifying the name of
109 * <code><input></code> element to create.
110 * @param {String} p_sValue String specifying the value of
111 * <code><input></code> element to create.
112 * @param {String} p_bChecked Boolean specifying if the
113 * <code><input></code> element is to be checked.
114 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
115 * one-html.html#ID-6043025">HTMLInputElement</a>}
117 function createInputElement(p_sType, p_sName, p_sValue, p_bChecked) {
122 if (Lang.isString(p_sType) && Lang.isString(p_sName)) {
127 For IE it is necessary to create the element with the
128 "type," "name," "value," and "checked" properties set all
132 sInput = "<input type=\"" + p_sType + "\" name=\"" +
137 sInput += " checked";
143 oInput = document.createElement(sInput);
148 oInput = document.createElement("input");
149 oInput.name = p_sName;
150 oInput.type = p_sType;
154 oInput.checked = true;
160 oInput.value = p_sValue;
170 * @method setAttributesFromSrcElement
171 * @description Gets the values for all the attributes of the source element
172 * (either <code><input></code> or <code><a></code>) that
173 * map to Button configuration attributes and sets them into a collection
174 * that is passed to the Button constructor.
176 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
177 * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org/
178 * TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-
179 * 48250443">HTMLAnchorElement</a>} p_oElement Object reference to the HTML
180 * element (either <code><input></code> or <code><span>
181 * </code>) used to create the button.
182 * @param {Object} p_oAttributes Object reference for the collection of
183 * configuration attributes used to create the button.
185 function setAttributesFromSrcElement(p_oElement, p_oAttributes) {
187 var sSrcElementNodeName = p_oElement.nodeName.toUpperCase(),
195 * @method setAttributeFromDOMAttribute
196 * @description Gets the value of the specified DOM attribute and sets it
197 * into the collection of configuration attributes used to configure
200 * @param {String} p_sAttribute String representing the name of the
201 * attribute to retrieve from the DOM element.
203 function setAttributeFromDOMAttribute(p_sAttribute) {
205 if (!(p_sAttribute in p_oAttributes)) {
208 Need to use "getAttributeNode" instead of "getAttribute"
209 because using "getAttribute," IE will return the innerText
210 of a <code><button></code> for the value attribute
211 rather than the value of the "value" attribute.
214 oAttribute = p_oElement.getAttributeNode(p_sAttribute);
217 if (oAttribute && ("value" in oAttribute)) {
220 p_oAttributes[p_sAttribute] = oAttribute.value;
230 * @method setFormElementProperties
231 * @description Gets the value of the attributes from the form element
232 * and sets them into the collection of configuration attributes used to
233 * configure the button.
236 function setFormElementProperties() {
238 setAttributeFromDOMAttribute("type");
240 if (p_oAttributes.type == "button") {
242 p_oAttributes.type = "push";
246 if (!("disabled" in p_oAttributes)) {
248 p_oAttributes.disabled = p_oElement.disabled;
252 setAttributeFromDOMAttribute("name");
253 setAttributeFromDOMAttribute("value");
254 setAttributeFromDOMAttribute("title");
259 switch (sSrcElementNodeName) {
263 p_oAttributes.type = "link";
265 setAttributeFromDOMAttribute("href");
266 setAttributeFromDOMAttribute("target");
272 setFormElementProperties();
274 if (!("checked" in p_oAttributes)) {
276 p_oAttributes.checked = p_oElement.checked;
284 setFormElementProperties();
286 oRootNode = p_oElement.parentNode.parentNode;
288 if (Dom.hasClass(oRootNode, this.CSS_CLASS_NAME + "-checked")) {
290 p_oAttributes.checked = true;
294 if (Dom.hasClass(oRootNode, this.CSS_CLASS_NAME + "-disabled")) {
296 p_oAttributes.disabled = true;
300 p_oElement.removeAttribute("value");
302 p_oElement.setAttribute("type", "button");
308 p_oElement.removeAttribute("id");
309 p_oElement.removeAttribute("name");
311 if (!("tabindex" in p_oAttributes)) {
313 p_oAttributes.tabindex = p_oElement.tabIndex;
317 if (!("label" in p_oAttributes)) {
319 // Set the "label" property
321 sText = sSrcElementNodeName == "INPUT" ?
322 p_oElement.value : p_oElement.innerHTML;
325 if (sText && sText.length > 0) {
327 p_oAttributes.label = sText;
338 * @description Initializes the set of configuration attributes that are
339 * used to instantiate the button.
341 * @param {Object} Object representing the button's set of
342 * configuration attributes.
344 function initConfig(p_oConfig) {
346 var oAttributes = p_oConfig.attributes,
347 oSrcElement = oAttributes.srcelement,
348 sSrcElementNodeName = oSrcElement.nodeName.toUpperCase(),
352 if (sSrcElementNodeName == this.NODE_NAME) {
354 p_oConfig.element = oSrcElement;
355 p_oConfig.id = oSrcElement.id;
357 Dom.getElementsBy(function (p_oElement) {
359 switch (p_oElement.nodeName.toUpperCase()) {
365 setAttributesFromSrcElement.call(me, p_oElement,
372 }, "*", oSrcElement);
377 switch (sSrcElementNodeName) {
383 setAttributesFromSrcElement.call(this, oSrcElement,
398 YAHOO.widget.Button = function (p_oElement, p_oAttributes) {
400 if (!Overlay && YAHOO.widget.Overlay) {
402 Overlay = YAHOO.widget.Overlay;
407 if (!Menu && YAHOO.widget.Menu) {
409 Menu = YAHOO.widget.Menu;
414 var fnSuperClass = YAHOO.widget.Button.superclass.constructor,
419 if (arguments.length == 1 && !Lang.isString(p_oElement) && !p_oElement.nodeName) {
421 if (!p_oElement.id) {
423 p_oElement.id = Dom.generateId();
429 fnSuperClass.call(this, (this.createButtonElement(p_oElement.type)), p_oElement);
434 oConfig = { element: null, attributes: (p_oAttributes || {}) };
437 if (Lang.isString(p_oElement)) {
439 oElement = Dom.get(p_oElement);
443 if (!oConfig.attributes.id) {
445 oConfig.attributes.id = p_oElement;
451 oConfig.attributes.srcelement = oElement;
453 initConfig.call(this, oConfig);
456 if (!oConfig.element) {
459 oConfig.element = this.createButtonElement(oConfig.attributes.type);
463 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
468 else if (p_oElement.nodeName) {
470 if (!oConfig.attributes.id) {
474 oConfig.attributes.id = p_oElement.id;
479 oConfig.attributes.id = Dom.generateId();
488 oConfig.attributes.srcelement = p_oElement;
490 initConfig.call(this, oConfig);
493 if (!oConfig.element) {
496 oConfig.element = this.createButtonElement(oConfig.attributes.type);
500 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
510 YAHOO.extend(YAHOO.widget.Button, YAHOO.util.Element, {
513 // Protected properties
518 * @description Object reference to the button's internal
519 * <code><a></code> or <code><button></code> element.
522 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
523 * level-one-html.html#ID-48250443">HTMLAnchorElement</a>|<a href="
524 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
525 * #ID-34812697">HTMLButtonElement</a>
532 * @description Object reference to the button's menu.
535 * @type {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|
536 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
542 * @property _hiddenFields
543 * @description Object reference to the <code><input></code>
544 * element, or array of HTML form elements used to represent the button
545 * when its parent form is submitted.
548 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
549 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array
555 * @property _onclickAttributeValue
556 * @description Object reference to the button's current value for the
557 * "onclick" configuration attribute.
562 _onclickAttributeValue: null,
566 * @property _activationKeyPressed
567 * @description Boolean indicating if the key(s) that toggle the button's
568 * "active" state have been pressed.
573 _activationKeyPressed: false,
577 * @property _activationButtonPressed
578 * @description Boolean indicating if the mouse button that toggles
579 * the button's "active" state has been pressed.
584 _activationButtonPressed: false,
588 * @property _hasKeyEventHandlers
589 * @description Boolean indicating if the button's "blur", "keydown" and
590 * "keyup" event handlers are assigned
595 _hasKeyEventHandlers: false,
599 * @property _hasMouseEventHandlers
600 * @description Boolean indicating if the button's "mouseout,"
601 * "mousedown," and "mouseup" event handlers are assigned
606 _hasMouseEventHandlers: false,
610 * @property _nOptionRegionX
611 * @description Number representing the X coordinate of the leftmost edge of the Button's
612 * option region. Applies only to Buttons of type "split".
625 * @property NODE_NAME
626 * @description The name of the node to be used for the button's
636 * @property CHECK_ACTIVATION_KEYS
637 * @description Array of numbers representing keys that (when pressed)
638 * toggle the button's "checked" attribute.
643 CHECK_ACTIVATION_KEYS: [32],
647 * @property ACTIVATION_KEYS
648 * @description Array of numbers representing keys that (when presed)
649 * toggle the button's "active" state.
654 ACTIVATION_KEYS: [13, 32],
658 * @property OPTION_AREA_WIDTH
659 * @description Width (in pixels) of the area of a split button that
660 * when pressed will display a menu.
665 OPTION_AREA_WIDTH: 20,
669 * @property CSS_CLASS_NAME
670 * @description String representing the CSS class(es) to be applied to
671 * the button's root element.
672 * @default "yui-button"
676 CSS_CLASS_NAME: "yui-button",
680 * @property RADIO_DEFAULT_TITLE
681 * @description String representing the default title applied to buttons
683 * @default "Unchecked. Click to check."
687 RADIO_DEFAULT_TITLE: "Unchecked. Click to check.",
691 * @property RADIO_CHECKED_TITLE
692 * @description String representing the title applied to buttons of
693 * type "radio" when checked.
694 * @default "Checked. Click another button to uncheck"
698 RADIO_CHECKED_TITLE: "Checked. Click another button to uncheck",
702 * @property CHECKBOX_DEFAULT_TITLE
703 * @description String representing the default title applied to
704 * buttons of type "checkbox."
705 * @default "Unchecked. Click to check."
709 CHECKBOX_DEFAULT_TITLE: "Unchecked. Click to check.",
713 * @property CHECKBOX_CHECKED_TITLE
714 * @description String representing the title applied to buttons of type
715 * "checkbox" when checked.
716 * @default "Checked. Click to uncheck."
720 CHECKBOX_CHECKED_TITLE: "Checked. Click to uncheck.",
724 * @property MENUBUTTON_DEFAULT_TITLE
725 * @description String representing the default title applied to
726 * buttons of type "menu."
727 * @default "Menu collapsed. Click to expand."
731 MENUBUTTON_DEFAULT_TITLE: "Menu collapsed. Click to expand.",
735 * @property MENUBUTTON_MENU_VISIBLE_TITLE
736 * @description String representing the title applied to buttons of type
737 * "menu" when the button's menu is visible.
738 * @default "Menu expanded. Click or press Esc to collapse."
742 MENUBUTTON_MENU_VISIBLE_TITLE:
743 "Menu expanded. Click or press Esc to collapse.",
747 * @property SPLITBUTTON_DEFAULT_TITLE
748 * @description String representing the default title applied to
749 * buttons of type "split."
750 * @default "Menu collapsed. Click inside option region or press
751 * Ctrl + Shift + M to show the menu."
755 SPLITBUTTON_DEFAULT_TITLE: ("Menu collapsed. Click inside option " +
756 "region or press down arrow key to show the menu."),
760 * @property SPLITBUTTON_OPTION_VISIBLE_TITLE
761 * @description String representing the title applied to buttons of type
762 * "split" when the button's menu is visible.
763 * @default "Menu expanded. Press Esc or Ctrl + Shift + M to hide
768 SPLITBUTTON_OPTION_VISIBLE_TITLE:
769 "Menu expanded. Press Esc to hide the menu.",
773 * @property SUBMIT_TITLE
774 * @description String representing the title applied to buttons of
776 * @default "Click to submit form."
780 SUBMIT_TITLE: "Click to submit form.",
784 // Protected attribute setter methods
789 * @description Sets the value of the button's "type" attribute.
791 * @param {String} p_sType String indicating the value for the button's
794 _setType: function (p_sType) {
796 if (p_sType == "split") {
798 this.on("option", this._onOption);
807 * @description Sets the value of the button's "label" attribute.
809 * @param {String} p_sLabel String indicating the value for the button's
812 _setLabel: function (p_sLabel) {
814 this._button.innerHTML = p_sLabel;
818 Remove and add the default class name from the root element
819 for Gecko to ensure that the button shrinkwraps to the label.
820 Without this the button will not be rendered at the correct
821 width when the label changes. The most likely cause for this
822 bug is button's use of the Gecko-specific CSS display type of
823 "-moz-inline-box" to simulate "inline-block" supported by IE,
828 nGeckoVersion = UA.gecko;
831 if (nGeckoVersion && nGeckoVersion < 1.9 && Dom.inDocument(this.get("element"))) {
833 sClass = this.CSS_CLASS_NAME;
835 this.removeClass(sClass);
837 Lang.later(0, this, this.addClass, sClass);
845 * @method _setTabIndex
846 * @description Sets the value of the button's "tabindex" attribute.
848 * @param {Number} p_nTabIndex Number indicating the value for the
849 * button's "tabindex" attribute.
851 _setTabIndex: function (p_nTabIndex) {
853 this._button.tabIndex = p_nTabIndex;
860 * @description Sets the value of the button's "title" attribute.
862 * @param {String} p_nTabIndex Number indicating the value for
863 * the button's "title" attribute.
865 _setTitle: function (p_sTitle) {
867 var sTitle = p_sTitle;
869 if (this.get("type") != "link") {
873 switch (this.get("type")) {
877 sTitle = this.RADIO_DEFAULT_TITLE;
883 sTitle = this.CHECKBOX_DEFAULT_TITLE;
889 sTitle = this.MENUBUTTON_DEFAULT_TITLE;
895 sTitle = this.SPLITBUTTON_DEFAULT_TITLE;
901 sTitle = this.SUBMIT_TITLE;
909 this._button.title = sTitle;
917 * @method _setDisabled
918 * @description Sets the value of the button's "disabled" attribute.
920 * @param {Boolean} p_bDisabled Boolean indicating the value for
921 * the button's "disabled" attribute.
923 _setDisabled: function (p_bDisabled) {
925 if (this.get("type") != "link") {
935 if (this.hasFocus()) {
941 this._button.setAttribute("disabled", "disabled");
943 this.addStateCSSClasses("disabled");
945 this.removeStateCSSClasses("hover");
946 this.removeStateCSSClasses("active");
947 this.removeStateCSSClasses("focus");
952 this._button.removeAttribute("disabled");
954 this.removeStateCSSClasses("disabled");
965 * @description Sets the value of the button's "href" attribute.
967 * @param {String} p_sHref String indicating the value for the button's
970 _setHref: function (p_sHref) {
972 if (this.get("type") == "link") {
974 this._button.href = p_sHref;
983 * @description Sets the value of the button's "target" attribute.
985 * @param {String} p_sTarget String indicating the value for the button's
986 * "target" attribute.
988 _setTarget: function (p_sTarget) {
990 if (this.get("type") == "link") {
992 this._button.setAttribute("target", p_sTarget);
1000 * @method _setChecked
1001 * @description Sets the value of the button's "target" attribute.
1003 * @param {Boolean} p_bChecked Boolean indicating the value for
1004 * the button's "checked" attribute.
1006 _setChecked: function (p_bChecked) {
1008 var sType = this.get("type"),
1011 if (sType == "checkbox" || sType == "radio") {
1015 this.addStateCSSClasses("checked");
1017 sTitle = (sType == "radio") ?
1018 this.RADIO_CHECKED_TITLE :
1019 this.CHECKBOX_CHECKED_TITLE;
1024 this.removeStateCSSClasses("checked");
1026 sTitle = (sType == "radio") ?
1027 this.RADIO_DEFAULT_TITLE :
1028 this.CHECKBOX_DEFAULT_TITLE;
1033 if (!this._hasDefaultTitle) {
1035 this.set("title", sTitle);
1046 * @description Sets the value of the button's "menu" attribute.
1048 * @param {Object} p_oMenu Object indicating the value for the button's
1051 _setMenu: function (p_oMenu) {
1053 var bLazyLoad = this.get("lazyloadmenu"),
1054 oButtonElement = this.get("element"),
1058 Boolean indicating if the value of p_oMenu is an instance
1059 of YAHOO.widget.Menu or YAHOO.widget.Overlay.
1068 function onAppendTo() {
1070 oMenu.render(oButtonElement.parentNode);
1072 this.removeListener("appendTo", onAppendTo);
1077 function setMenuContainer() {
1079 oMenu.cfg.queueProperty("container", oButtonElement.parentNode);
1081 this.removeListener("appendTo", setMenuContainer);
1086 function initMenu() {
1092 Dom.addClass(oMenu.element, this.get("menuclassname"));
1093 Dom.addClass(oMenu.element, "yui-" + this.get("type") + "-button-menu");
1095 oMenu.showEvent.subscribe(this._onMenuShow, null, this);
1096 oMenu.hideEvent.subscribe(this._onMenuHide, null, this);
1097 oMenu.renderEvent.subscribe(this._onMenuRender, null, this);
1100 if (Menu && oMenu instanceof Menu) {
1104 oContainer = this.get("container");
1108 oMenu.cfg.queueProperty("container", oContainer);
1113 this.on("appendTo", setMenuContainer);
1119 oMenu.cfg.queueProperty("clicktohide", false);
1121 oMenu.keyDownEvent.subscribe(this._onMenuKeyDown, this, true);
1122 oMenu.subscribe("click", this._onMenuClick, this, true);
1124 this.on("selectedMenuItemChange", this._onSelectedMenuItemChange);
1126 oSrcElement = oMenu.srcElement;
1128 if (oSrcElement && oSrcElement.nodeName.toUpperCase() == "SELECT") {
1130 oSrcElement.style.display = "none";
1131 oSrcElement.parentNode.removeChild(oSrcElement);
1136 else if (Overlay && oMenu instanceof Overlay) {
1138 if (!m_oOverlayManager) {
1140 m_oOverlayManager = new YAHOO.widget.OverlayManager();
1144 m_oOverlayManager.register(oMenu);
1152 if (!bInstance && !bLazyLoad) {
1154 if (Dom.inDocument(oButtonElement)) {
1156 oMenu.render(oButtonElement.parentNode);
1161 this.on("appendTo", onAppendTo);
1176 sMenuCSSClassName = Menu.prototype.CSS_CLASS_NAME;
1180 if (p_oMenu && Menu && (p_oMenu instanceof Menu)) {
1185 initMenu.call(this);
1188 else if (Overlay && p_oMenu && (p_oMenu instanceof Overlay)) {
1193 oMenu.cfg.queueProperty("visible", false);
1195 initMenu.call(this);
1198 else if (Menu && Lang.isArray(p_oMenu)) {
1200 oMenu = new Menu(Dom.generateId(), { lazyload: bLazyLoad, itemdata: p_oMenu });
1204 this.on("appendTo", initMenu);
1207 else if (Lang.isString(p_oMenu)) {
1209 oMenuElement = Dom.get(p_oMenu);
1213 if (Menu && Dom.hasClass(oMenuElement, sMenuCSSClassName) ||
1214 oMenuElement.nodeName.toUpperCase() == "SELECT") {
1216 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1218 initMenu.call(this);
1223 oMenu = new Overlay(p_oMenu, { visible: false });
1225 initMenu.call(this);
1232 else if (p_oMenu && p_oMenu.nodeName) {
1234 if (Menu && Dom.hasClass(p_oMenu, sMenuCSSClassName) ||
1235 p_oMenu.nodeName.toUpperCase() == "SELECT") {
1237 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1239 initMenu.call(this);
1246 Dom.generateId(p_oMenu);
1250 oMenu = new Overlay(p_oMenu, { visible: false });
1252 initMenu.call(this);
1264 * @method _setOnClick
1265 * @description Sets the value of the button's "onclick" attribute.
1267 * @param {Object} p_oObject Object indicating the value for the button's
1268 * "onclick" attribute.
1270 _setOnClick: function (p_oObject) {
1273 Remove any existing listeners if a "click" event handler
1274 has already been specified.
1277 if (this._onclickAttributeValue &&
1278 (this._onclickAttributeValue != p_oObject)) {
1280 this.removeListener("click", this._onclickAttributeValue.fn);
1282 this._onclickAttributeValue = null;
1287 if (!this._onclickAttributeValue &&
1288 Lang.isObject(p_oObject) &&
1289 Lang.isFunction(p_oObject.fn)) {
1291 this.on("click", p_oObject.fn, p_oObject.obj, p_oObject.scope);
1293 this._onclickAttributeValue = p_oObject;
1301 // Protected methods
1306 * @method _isActivationKey
1307 * @description Determines if the specified keycode is one that toggles
1308 * the button's "active" state.
1310 * @param {Number} p_nKeyCode Number representing the keycode to
1314 _isActivationKey: function (p_nKeyCode) {
1316 var sType = this.get("type"),
1317 aKeyCodes = (sType == "checkbox" || sType == "radio") ?
1318 this.CHECK_ACTIVATION_KEYS : this.ACTIVATION_KEYS,
1320 nKeyCodes = aKeyCodes.length,
1325 if (nKeyCodes > 0) {
1331 if (p_nKeyCode == aKeyCodes[i]) {
1349 * @method _isSplitButtonOptionKey
1350 * @description Determines if the specified keycode is one that toggles
1351 * the display of the split button's menu.
1353 * @param {Event} p_oEvent Object representing the DOM event object
1354 * passed back by the event utility (YAHOO.util.Event).
1357 _isSplitButtonOptionKey: function (p_oEvent) {
1359 var bShowMenu = (Event.getCharCode(p_oEvent) == 40);
1362 var onKeyPress = function (p_oEvent) {
1364 Event.preventDefault(p_oEvent);
1366 this.removeListener("keypress", onKeyPress);
1371 // Prevent the browser from scrolling the window
1376 this.on("keypress", onKeyPress);
1380 Event.preventDefault(p_oEvent);
1389 * @method _addListenersToForm
1390 * @description Adds event handlers to the button's form.
1393 _addListenersToForm: function () {
1395 var oForm = this.getForm(),
1396 onFormKeyPress = YAHOO.widget.Button.onFormKeyPress,
1397 bHasKeyPressListener,
1406 Event.on(oForm, "reset", this._onFormReset, null, this);
1407 Event.on(oForm, "submit", this._onFormSubmit, null, this);
1409 oSrcElement = this.get("srcelement");
1412 if (this.get("type") == "submit" ||
1413 (oSrcElement && oSrcElement.type == "submit"))
1416 aListeners = Event.getListeners(oForm, "keypress");
1417 bHasKeyPressListener = false;
1421 nListeners = aListeners.length;
1423 if (nListeners > 0) {
1429 if (aListeners[i].fn == onFormKeyPress) {
1431 bHasKeyPressListener = true;
1444 if (!bHasKeyPressListener) {
1446 Event.on(oForm, "keypress", onFormKeyPress);
1460 * @description Shows the button's menu.
1462 * @param {Event} p_oEvent Object representing the DOM event object
1463 * passed back by the event utility (YAHOO.util.Event) that triggered
1464 * the display of the menu.
1466 _showMenu: function (p_oEvent) {
1468 if (YAHOO.widget.MenuManager) {
1469 YAHOO.widget.MenuManager.hideVisible();
1473 if (m_oOverlayManager) {
1474 m_oOverlayManager.hideAll();
1478 var oMenu = this._menu,
1479 aMenuAlignment = this.get("menualignment"),
1480 bFocusMenu = this.get("focusmenu"),
1484 if (this._renderedMenu) {
1486 oMenu.cfg.setProperty("context",
1487 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1489 oMenu.cfg.setProperty("preventcontextoverlap", true);
1490 oMenu.cfg.setProperty("constraintoviewport", true);
1495 oMenu.cfg.queueProperty("context",
1496 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1498 oMenu.cfg.queueProperty("preventcontextoverlap", true);
1499 oMenu.cfg.queueProperty("constraintoviewport", true);
1505 Refocus the Button before showing its Menu in case the call to
1506 YAHOO.widget.MenuManager.hideVisible() resulted in another element in the
1507 DOM being focused after another Menu was hidden.
1513 if (Menu && oMenu && (oMenu instanceof Menu)) {
1515 // Since Menus automatically focus themselves when made visible, temporarily
1516 // replace the Menu focus method so that the value of the Button's "focusmenu"
1517 // attribute determines if the Menu should be focus when made visible.
1519 fnFocusMethod = oMenu.focus;
1521 oMenu.focus = function () {};
1523 if (this._renderedMenu) {
1525 oMenu.cfg.setProperty("minscrollheight", this.get("menuminscrollheight"));
1526 oMenu.cfg.setProperty("maxheight", this.get("menumaxheight"));
1531 oMenu.cfg.queueProperty("minscrollheight", this.get("menuminscrollheight"));
1532 oMenu.cfg.queueProperty("maxheight", this.get("menumaxheight"));
1539 oMenu.focus = fnFocusMethod;
1545 Stop the propagation of the event so that the MenuManager
1546 doesn't blur the menu after it gets focus.
1549 if (p_oEvent.type == "mousedown") {
1550 Event.stopPropagation(p_oEvent);
1559 else if (Overlay && oMenu && (oMenu instanceof Overlay)) {
1561 if (!this._renderedMenu) {
1562 oMenu.render(this.get("element").parentNode);
1575 * @description Hides the button's menu.
1578 _hideMenu: function () {
1580 var oMenu = this._menu;
1593 // Protected event handlers
1597 * @method _onMouseOver
1598 * @description "mouseover" event handler for the button.
1600 * @param {Event} p_oEvent Object representing the DOM event object
1601 * passed back by the event utility (YAHOO.util.Event).
1603 _onMouseOver: function (p_oEvent) {
1605 var sType = this.get("type"),
1610 if (sType === "split") {
1612 oElement = this.get("element");
1614 (Dom.getX(oElement) + (oElement.offsetWidth - this.OPTION_AREA_WIDTH));
1616 this._nOptionRegionX = nOptionRegionX;
1621 if (!this._hasMouseEventHandlers) {
1623 if (sType === "split") {
1625 this.on("mousemove", this._onMouseMove);
1629 this.on("mouseout", this._onMouseOut);
1631 this._hasMouseEventHandlers = true;
1636 this.addStateCSSClasses("hover");
1639 if (sType === "split" && (Event.getPageX(p_oEvent) > nOptionRegionX)) {
1641 this.addStateCSSClasses("hoveroption");
1646 if (this._activationButtonPressed) {
1648 this.addStateCSSClasses("active");
1653 if (this._bOptionPressed) {
1655 this.addStateCSSClasses("activeoption");
1660 if (this._activationButtonPressed || this._bOptionPressed) {
1662 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1670 * @method _onMouseMove
1671 * @description "mousemove" event handler for the button.
1673 * @param {Event} p_oEvent Object representing the DOM event object
1674 * passed back by the event utility (YAHOO.util.Event).
1676 _onMouseMove: function (p_oEvent) {
1678 var nOptionRegionX = this._nOptionRegionX;
1680 if (nOptionRegionX) {
1682 if (Event.getPageX(p_oEvent) > nOptionRegionX) {
1684 this.addStateCSSClasses("hoveroption");
1689 this.removeStateCSSClasses("hoveroption");
1698 * @method _onMouseOut
1699 * @description "mouseout" event handler for the button.
1701 * @param {Event} p_oEvent Object representing the DOM event object
1702 * passed back by the event utility (YAHOO.util.Event).
1704 _onMouseOut: function (p_oEvent) {
1706 var sType = this.get("type");
1708 this.removeStateCSSClasses("hover");
1711 if (sType != "menu") {
1713 this.removeStateCSSClasses("active");
1718 if (this._activationButtonPressed || this._bOptionPressed) {
1720 Event.on(document, "mouseup", this._onDocumentMouseUp, null, this);
1725 if (sType === "split" && (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
1727 this.removeStateCSSClasses("hoveroption");
1735 * @method _onDocumentMouseUp
1736 * @description "mouseup" event handler for the button.
1738 * @param {Event} p_oEvent Object representing the DOM event object
1739 * passed back by the event utility (YAHOO.util.Event).
1741 _onDocumentMouseUp: function (p_oEvent) {
1743 this._activationButtonPressed = false;
1744 this._bOptionPressed = false;
1746 var sType = this.get("type"),
1750 if (sType == "menu" || sType == "split") {
1752 oTarget = Event.getTarget(p_oEvent);
1753 oMenuElement = this._menu.element;
1755 if (oTarget != oMenuElement &&
1756 !Dom.isAncestor(oMenuElement, oTarget)) {
1758 this.removeStateCSSClasses((sType == "menu" ?
1759 "active" : "activeoption"));
1767 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1773 * @method _onMouseDown
1774 * @description "mousedown" event handler for the button.
1776 * @param {Event} p_oEvent Object representing the DOM event object
1777 * passed back by the event utility (YAHOO.util.Event).
1779 _onMouseDown: function (p_oEvent) {
1785 function onMouseUp() {
1788 this.removeListener("mouseup", onMouseUp);
1793 if ((p_oEvent.which || p_oEvent.button) == 1) {
1796 if (!this.hasFocus()) {
1803 sType = this.get("type");
1806 if (sType == "split") {
1808 if (Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1810 this.fireEvent("option", p_oEvent);
1816 this.addStateCSSClasses("active");
1818 this._activationButtonPressed = true;
1823 else if (sType == "menu") {
1825 if (this.isActive()) {
1829 this._activationButtonPressed = false;
1834 this._showMenu(p_oEvent);
1836 this._activationButtonPressed = true;
1843 this.addStateCSSClasses("active");
1845 this._activationButtonPressed = true;
1851 if (sType == "split" || sType == "menu") {
1853 this._hideMenuTimer = Lang.later(250, this, this.on, ["mouseup", onMouseUp]);
1865 * @method _onMouseUp
1866 * @description "mouseup" event handler for the button.
1868 * @param {Event} p_oEvent Object representing the DOM event object
1869 * passed back by the event utility (YAHOO.util.Event).
1871 _onMouseUp: function (p_oEvent) {
1873 var sType = this.get("type"),
1874 oHideMenuTimer = this._hideMenuTimer,
1878 if (oHideMenuTimer) {
1880 oHideMenuTimer.cancel();
1885 if (sType == "checkbox" || sType == "radio") {
1887 this.set("checked", !(this.get("checked")));
1892 this._activationButtonPressed = false;
1895 if (sType != "menu") {
1897 this.removeStateCSSClasses("active");
1902 if (sType == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1915 * @description "focus" event handler for the button.
1917 * @param {Event} p_oEvent Object representing the DOM event object
1918 * passed back by the event utility (YAHOO.util.Event).
1920 _onFocus: function (p_oEvent) {
1924 this.addStateCSSClasses("focus");
1926 if (this._activationKeyPressed) {
1928 this.addStateCSSClasses("active");
1932 m_oFocusedButton = this;
1935 if (!this._hasKeyEventHandlers) {
1937 oElement = this._button;
1939 Event.on(oElement, "blur", this._onBlur, null, this);
1940 Event.on(oElement, "keydown", this._onKeyDown, null, this);
1941 Event.on(oElement, "keyup", this._onKeyUp, null, this);
1943 this._hasKeyEventHandlers = true;
1948 this.fireEvent("focus", p_oEvent);
1955 * @description "blur" event handler for the button.
1957 * @param {Event} p_oEvent Object representing the DOM event object
1958 * passed back by the event utility (YAHOO.util.Event).
1960 _onBlur: function (p_oEvent) {
1962 this.removeStateCSSClasses("focus");
1964 if (this.get("type") != "menu") {
1966 this.removeStateCSSClasses("active");
1970 if (this._activationKeyPressed) {
1972 Event.on(document, "keyup", this._onDocumentKeyUp, null, this);
1977 m_oFocusedButton = null;
1979 this.fireEvent("blur", p_oEvent);
1985 * @method _onDocumentKeyUp
1986 * @description "keyup" event handler for the document.
1988 * @param {Event} p_oEvent Object representing the DOM event object
1989 * passed back by the event utility (YAHOO.util.Event).
1991 _onDocumentKeyUp: function (p_oEvent) {
1993 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1995 this._activationKeyPressed = false;
1997 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
2005 * @method _onKeyDown
2006 * @description "keydown" event handler for the button.
2008 * @param {Event} p_oEvent Object representing the DOM event object
2009 * passed back by the event utility (YAHOO.util.Event).
2011 _onKeyDown: function (p_oEvent) {
2013 var oMenu = this._menu;
2016 if (this.get("type") == "split" &&
2017 this._isSplitButtonOptionKey(p_oEvent)) {
2019 this.fireEvent("option", p_oEvent);
2022 else if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
2024 if (this.get("type") == "menu") {
2026 this._showMenu(p_oEvent);
2031 this._activationKeyPressed = true;
2033 this.addStateCSSClasses("active");
2040 if (oMenu && oMenu.cfg.getProperty("visible") &&
2041 Event.getCharCode(p_oEvent) == 27) {
2053 * @description "keyup" event handler for the button.
2055 * @param {Event} p_oEvent Object representing the DOM event object
2056 * passed back by the event utility (YAHOO.util.Event).
2058 _onKeyUp: function (p_oEvent) {
2062 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
2064 sType = this.get("type");
2066 if (sType == "checkbox" || sType == "radio") {
2068 this.set("checked", !(this.get("checked")));
2072 this._activationKeyPressed = false;
2074 if (this.get("type") != "menu") {
2076 this.removeStateCSSClasses("active");
2087 * @description "click" event handler for the button.
2089 * @param {Event} p_oEvent Object representing the DOM event object
2090 * passed back by the event utility (YAHOO.util.Event).
2092 _onClick: function (p_oEvent) {
2094 var sType = this.get("type"),
2106 if (!this._hasDefaultTitle) {
2108 if (this.get("checked")) {
2110 sTitle = (sType == "radio") ?
2111 this.RADIO_CHECKED_TITLE :
2112 this.CHECKBOX_CHECKED_TITLE;
2117 sTitle = (sType == "radio") ?
2118 this.RADIO_DEFAULT_TITLE :
2119 this.CHECKBOX_DEFAULT_TITLE;
2123 this.set("title", sTitle);
2131 if (p_oEvent.returnValue !== false) {
2141 oForm = this.getForm();
2153 sTitle = this._menu.cfg.getProperty("visible") ?
2154 this.MENUBUTTON_MENU_VISIBLE_TITLE :
2155 this.MENUBUTTON_DEFAULT_TITLE;
2157 this.set("title", sTitle);
2163 if (this._nOptionRegionX > 0 &&
2164 (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
2173 oSrcElement = this.get("srcelement");
2175 if (oSrcElement && oSrcElement.type == "submit" &&
2176 p_oEvent.returnValue !== false) {
2184 sTitle = this._menu.cfg.getProperty("visible") ?
2185 this.SPLITBUTTON_OPTION_VISIBLE_TITLE :
2186 this.SPLITBUTTON_DEFAULT_TITLE;
2188 this.set("title", sTitle);
2200 * @method _onDblClick
2201 * @description "dblclick" event handler for the button.
2203 * @param {Event} p_oEvent Object representing the DOM event object
2204 * passed back by the event utility (YAHOO.util.Event).
2206 _onDblClick: function (p_oEvent) {
2208 var bReturnVal = true;
2210 if (this.get("type") == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
2222 * @method _onAppendTo
2223 * @description "appendTo" event handler for the button.
2225 * @param {Event} p_oEvent Object representing the DOM event object
2226 * passed back by the event utility (YAHOO.util.Event).
2228 _onAppendTo: function (p_oEvent) {
2231 It is necessary to call "_addListenersToForm" using
2232 "setTimeout" to make sure that the button's "form" property
2233 returns a node reference. Sometimes, if you try to get the
2234 reference immediately after appending the field, it is null.
2237 Lang.later(0, this, this._addListenersToForm);
2243 * @method _onFormReset
2244 * @description "reset" event handler for the button's form.
2246 * @param {Event} p_oEvent Object representing the DOM event
2247 * object passed back by the event utility (YAHOO.util.Event).
2249 _onFormReset: function (p_oEvent) {
2251 var sType = this.get("type"),
2254 if (sType == "checkbox" || sType == "radio") {
2256 this.resetValue("checked");
2261 if (Menu && oMenu && (oMenu instanceof Menu)) {
2263 this.resetValue("selectedMenuItem");
2271 * @method _onFormSubmit
2272 * @description "submit" event handler for the button's form.
2274 * @param {Event} p_oEvent Object representing the DOM event
2275 * object passed back by the event utility (YAHOO.util.Event).
2277 _onFormSubmit: function (p_oEvent) {
2279 this.createHiddenFields();
2285 * @method _onDocumentMouseDown
2286 * @description "mousedown" event handler for the document.
2288 * @param {Event} p_oEvent Object representing the DOM event object
2289 * passed back by the event utility (YAHOO.util.Event).
2291 _onDocumentMouseDown: function (p_oEvent) {
2293 var oTarget = Event.getTarget(p_oEvent),
2294 oButtonElement = this.get("element"),
2295 oMenuElement = this._menu.element;
2298 if (oTarget != oButtonElement &&
2299 !Dom.isAncestor(oButtonElement, oTarget) &&
2300 oTarget != oMenuElement &&
2301 !Dom.isAncestor(oMenuElement, oTarget)) {
2305 Event.removeListener(document, "mousedown",
2306 this._onDocumentMouseDown);
2315 * @description "option" event handler for the button.
2317 * @param {Event} p_oEvent Object representing the DOM event object
2318 * passed back by the event utility (YAHOO.util.Event).
2320 _onOption: function (p_oEvent) {
2322 if (this.hasClass("yui-split-button-activeoption")) {
2326 this._bOptionPressed = false;
2331 this._showMenu(p_oEvent);
2333 this._bOptionPressed = true;
2341 * @method _onMenuShow
2342 * @description "show" event handler for the button's menu.
2344 * @param {String} p_sType String representing the name of the event
2347 _onMenuShow: function (p_sType) {
2349 Event.on(document, "mousedown", this._onDocumentMouseDown,
2355 if (this.get("type") == "split") {
2357 sTitle = this.SPLITBUTTON_OPTION_VISIBLE_TITLE;
2358 sState = "activeoption";
2363 sTitle = this.MENUBUTTON_MENU_VISIBLE_TITLE;
2368 this.addStateCSSClasses(sState);
2369 this.set("title", sTitle);
2375 * @method _onMenuHide
2376 * @description "hide" event handler for the button's menu.
2378 * @param {String} p_sType String representing the name of the event
2381 _onMenuHide: function (p_sType) {
2383 var oMenu = this._menu,
2388 if (this.get("type") == "split") {
2390 sTitle = this.SPLITBUTTON_DEFAULT_TITLE;
2391 sState = "activeoption";
2396 sTitle = this.MENUBUTTON_DEFAULT_TITLE;
2401 this.removeStateCSSClasses(sState);
2402 this.set("title", sTitle);
2405 if (this.get("type") == "split") {
2407 this._bOptionPressed = false;
2415 * @method _onMenuKeyDown
2416 * @description "keydown" event handler for the button's menu.
2418 * @param {String} p_sType String representing the name of the event
2420 * @param {Array} p_aArgs Array of arguments sent when the event
2423 _onMenuKeyDown: function (p_sType, p_aArgs) {
2425 var oEvent = p_aArgs[0];
2427 if (Event.getCharCode(oEvent) == 27) {
2431 if (this.get("type") == "split") {
2433 this._bOptionPressed = false;
2443 * @method _onMenuRender
2444 * @description "render" event handler for the button's menu.
2446 * @param {String} p_sType String representing the name of the
2447 * event thatwas fired.
2449 _onMenuRender: function (p_sType) {
2451 var oButtonElement = this.get("element"),
2452 oButtonParent = oButtonElement.parentNode,
2454 oMenuElement = oMenu.element,
2455 oSrcElement = oMenu.srcElement;
2458 if (oButtonParent != oMenuElement.parentNode) {
2460 oButtonParent.appendChild(oMenuElement);
2464 this._renderedMenu = true;
2466 // If the user has designated an <option> of the Menu's source
2467 // <select> element to be selected, sync the selectedIndex with
2468 // the "selectedMenuItem" Attribute.
2471 oSrcElement.nodeName.toLowerCase() === "select" &&
2472 oSrcElement.value) {
2474 this.set("selectedMenuItem",
2475 oMenu.getItem(oSrcElement.selectedIndex));
2484 * @method _onMenuClick
2485 * @description "click" event handler for the button's menu.
2487 * @param {String} p_sType String representing the name of the event
2489 * @param {Array} p_aArgs Array of arguments sent when the event
2492 _onMenuClick: function (p_sType, p_aArgs) {
2494 var oItem = p_aArgs[1],
2499 this.set("selectedMenuItem", oItem);
2501 oSrcElement = this.get("srcelement");
2503 if (oSrcElement && oSrcElement.type == "submit") {
2517 * @method _onSelectedMenuItemChange
2518 * @description "selectedMenuItemChange" event handler for the Button's
2519 * "selectedMenuItem" attribute.
2520 * @param {Event} event Object representing the DOM event object
2521 * passed back by the event utility (YAHOO.util.Event).
2523 _onSelectedMenuItemChange: function (event) {
2525 var oSelected = event.prevValue,
2526 oItem = event.newValue;
2529 Dom.removeClass(oSelected.element, "yui-button-selectedmenuitem");
2533 Dom.addClass(oItem.element, "yui-button-selectedmenuitem");
2543 * @method createButtonElement
2544 * @description Creates the button's HTML elements.
2545 * @param {String} p_sType String indicating the type of element
2547 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2548 * level-one-html.html#ID-58190037">HTMLElement</a>}
2550 createButtonElement: function (p_sType) {
2552 var sNodeName = this.NODE_NAME,
2553 oElement = document.createElement(sNodeName);
2555 oElement.innerHTML = "<" + sNodeName + " class=\"first-child\">" +
2556 (p_sType == "link" ? "<a></a>" :
2557 "<button type=\"button\"></button>") + "</" + sNodeName + ">";
2565 * @method addStateCSSClasses
2566 * @description Appends state-specific CSS classes to the button's root
2569 addStateCSSClasses: function (p_sState) {
2571 var sType = this.get("type");
2573 if (Lang.isString(p_sState)) {
2575 if (p_sState != "activeoption" && p_sState != "hoveroption") {
2577 this.addClass(this.CSS_CLASS_NAME + ("-" + p_sState));
2581 this.addClass("yui-" + sType + ("-button-" + p_sState));
2589 * @method removeStateCSSClasses
2590 * @description Removes state-specific CSS classes to the button's root
2593 removeStateCSSClasses: function (p_sState) {
2595 var sType = this.get("type");
2597 if (Lang.isString(p_sState)) {
2599 this.removeClass(this.CSS_CLASS_NAME + ("-" + p_sState));
2600 this.removeClass("yui-" + sType + ("-button-" + p_sState));
2608 * @method createHiddenFields
2609 * @description Creates the button's hidden form field and appends it
2610 * to its parent form.
2611 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2612 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
2614 createHiddenFields: function () {
2616 this.removeHiddenFields();
2618 var oForm = this.getForm(),
2630 bMenuSrcElementIsSelect = false;
2633 if (oForm && !this.get("disabled")) {
2635 sType = this.get("type");
2636 bCheckable = (sType == "checkbox" || sType == "radio");
2639 if ((bCheckable && this.get("checked")) || (m_oSubmitTrigger == this)) {
2642 oButtonField = createInputElement((bCheckable ? sType : "hidden"),
2643 this.get("name"), this.get("value"), this.get("checked"));
2650 oButtonField.style.display = "none";
2654 oForm.appendChild(oButtonField);
2664 if (Menu && oMenu && (oMenu instanceof Menu)) {
2667 oMenuItem = this.get("selectedMenuItem");
2668 oMenuSrcElement = oMenu.srcElement;
2669 bMenuSrcElementIsSelect = (oMenuSrcElement &&
2670 oMenuSrcElement.nodeName.toUpperCase() == "SELECT");
2674 oValue = (oMenuItem.value === null || oMenuItem.value === "") ?
2675 oMenuItem.cfg.getProperty("text") : oMenuItem.value;
2677 sButtonName = this.get("name");
2680 if (bMenuSrcElementIsSelect) {
2682 sMenuFieldName = oMenuSrcElement.name;
2685 else if (sButtonName) {
2687 sMenuFieldName = (sButtonName + "_options");
2692 if (oValue && sMenuFieldName) {
2694 oMenuField = createInputElement("hidden", sMenuFieldName, oValue);
2695 oForm.appendChild(oMenuField);
2700 else if (bMenuSrcElementIsSelect) {
2702 oForm.appendChild(oMenuSrcElement);
2709 if (oButtonField && oMenuField) {
2711 this._hiddenFields = [oButtonField, oMenuField];
2714 else if (!oButtonField && oMenuField) {
2716 this._hiddenFields = oMenuField;
2719 else if (oButtonField && !oMenuField) {
2721 this._hiddenFields = oButtonField;
2725 oReturnVal = this._hiddenFields;
2735 * @method removeHiddenFields
2736 * @description Removes the button's hidden form field(s) from its
2739 removeHiddenFields: function () {
2741 var oField = this._hiddenFields,
2745 function removeChild(p_oElement) {
2747 if (Dom.inDocument(p_oElement)) {
2749 p_oElement.parentNode.removeChild(p_oElement);
2758 if (Lang.isArray(oField)) {
2760 nFields = oField.length;
2768 removeChild(oField[i]);
2778 removeChild(oField);
2782 this._hiddenFields = null;
2790 * @method submitForm
2791 * @description Submits the form to which the button belongs. Returns
2792 * true if the form was submitted successfully, false if the submission
2797 submitForm: function () {
2799 var oForm = this.getForm(),
2801 oSrcElement = this.get("srcelement"),
2804 Boolean indicating if the event fired successfully
2805 (was not cancelled by any handlers)
2808 bSubmitForm = false,
2815 if (this.get("type") == "submit" || (oSrcElement && oSrcElement.type == "submit")) {
2817 m_oSubmitTrigger = this;
2824 bSubmitForm = oForm.fireEvent("onsubmit");
2827 else { // Gecko, Opera, and Safari
2829 oEvent = document.createEvent("HTMLEvents");
2830 oEvent.initEvent("submit", true, true);
2832 bSubmitForm = oForm.dispatchEvent(oEvent);
2838 In IE and Safari, dispatching a "submit" event to a form
2839 WILL cause the form's "submit" event to fire, but WILL NOT
2840 submit the form. Therefore, we need to call the "submit"
2844 if ((UA.ie || UA.webkit) && bSubmitForm) {
2859 * @description The Button class's initialization method.
2860 * @param {String} p_oElement String specifying the id attribute of the
2861 * <code><input></code>, <code><button></code>,
2862 * <code><a></code>, or <code><span></code> element to
2863 * be used to create the button.
2864 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2865 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://
2866 * www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
2867 * #ID-34812697">HTMLButtonElement</a>|<a href="http://www.w3.org/TR
2868 * /2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-33759296">
2869 * HTMLElement</a>} p_oElement Object reference for the
2870 * <code><input></code>, <code><button></code>,
2871 * <code><a></code>, or <code><span></code> element to be
2872 * used to create the button.
2873 * @param {Object} p_oElement Object literal specifying a set of
2874 * configuration attributes used to create the button.
2875 * @param {Object} p_oAttributes Optional. Object literal specifying a
2876 * set of configuration attributes used to create the button.
2878 init: function (p_oElement, p_oAttributes) {
2880 var sNodeName = p_oAttributes.type == "link" ? "a" : "button",
2881 oSrcElement = p_oAttributes.srcelement,
2882 oButton = p_oElement.getElementsByTagName(sNodeName)[0],
2888 oInput = p_oElement.getElementsByTagName("input")[0];
2893 oButton = document.createElement("button");
2894 oButton.setAttribute("type", "button");
2896 oInput.parentNode.replaceChild(oButton, oInput);
2902 this._button = oButton;
2905 Capture if the button has a value for the title attribute. If so, we won't
2906 override it for type of "checkbox" or "radio".
2909 this._hasDefaultTitle = (p_oAttributes.title && p_oAttributes.title.length > 0);
2911 YAHOO.widget.Button.superclass.init.call(this, p_oElement, p_oAttributes);
2914 var sId = this.get("id"),
2915 sButtonId = sId + "-button";
2918 oButton.id = sButtonId;
2925 var hasLabel = function (element) {
2927 return (element.htmlFor === sId);
2932 var setLabel = function () {
2934 oLabel.setAttribute((UA.ie ? "htmlFor" : "for"), sButtonId);
2939 if (oSrcElement && this.get("type") != "link") {
2941 aLabels = Dom.getElementsBy(hasLabel, "label");
2943 if (Lang.isArray(aLabels) && aLabels.length > 0) {
2945 oLabel = aLabels[0];
2952 m_oButtons[sId] = this;
2955 this.addClass(this.CSS_CLASS_NAME);
2956 this.addClass("yui-" + this.get("type") + "-button");
2958 Event.on(this._button, "focus", this._onFocus, null, this);
2959 this.on("mouseover", this._onMouseOver);
2960 this.on("mousedown", this._onMouseDown);
2961 this.on("mouseup", this._onMouseUp);
2962 this.on("click", this._onClick);
2964 // Need to reset the value of the "onclick" Attribute so that any
2965 // handlers registered via the "onclick" Attribute are fired after
2966 // Button's default "_onClick" listener.
2968 var fnOnClick = this.get("onclick");
2970 this.set("onclick", null);
2971 this.set("onclick", fnOnClick);
2973 this.on("dblclick", this._onDblClick);
2977 this.on("appendTo", setLabel);
2981 this.on("appendTo", this._onAppendTo);
2985 var oContainer = this.get("container"),
2986 oElement = this.get("element"),
2987 bElInDoc = Dom.inDocument(oElement),
2993 if (oSrcElement && oSrcElement != oElement) {
2995 oParentNode = oSrcElement.parentNode;
2999 oParentNode.removeChild(oSrcElement);
3005 if (Lang.isString(oContainer)) {
3007 Event.onContentReady(oContainer, this.appendTo, oContainer, this);
3012 this.on("init", function () {
3014 Lang.later(0, this, this.appendTo, oContainer);
3021 else if (!bElInDoc && oSrcElement && oSrcElement != oElement) {
3023 oParentNode = oSrcElement.parentNode;
3027 this.fireEvent("beforeAppendTo", {
3028 type: "beforeAppendTo",
3032 oParentNode.replaceChild(oElement, oSrcElement);
3034 this.fireEvent("appendTo", {
3042 else if (this.get("type") != "link" && bElInDoc && oSrcElement &&
3043 oSrcElement == oElement) {
3045 this._addListenersToForm();
3051 this.fireEvent("init", {
3060 * @method initAttributes
3061 * @description Initializes all of the configuration attributes used to
3062 * create the button.
3063 * @param {Object} p_oAttributes Object literal specifying a set of
3064 * configuration attributes used to create the button.
3066 initAttributes: function (p_oAttributes) {
3068 var oAttributes = p_oAttributes || {};
3070 YAHOO.widget.Button.superclass.initAttributes.call(this,
3076 * @description String specifying the button's type. Possible
3077 * values are: "push," "link," "submit," "reset," "checkbox,"
3078 * "radio," "menu," and "split."
3083 this.setAttributeConfig("type", {
3085 value: (oAttributes.type || "push"),
3086 validator: Lang.isString,
3088 method: this._setType
3095 * @description String specifying the button's text label
3100 this.setAttributeConfig("label", {
3102 value: oAttributes.label,
3103 validator: Lang.isString,
3104 method: this._setLabel
3111 * @description Object specifying the value for the button.
3115 this.setAttributeConfig("value", {
3117 value: oAttributes.value
3124 * @description String specifying the name for the button.
3128 this.setAttributeConfig("name", {
3130 value: oAttributes.name,
3131 validator: Lang.isString
3137 * @attribute tabindex
3138 * @description Number specifying the tabindex for the button.
3142 this.setAttributeConfig("tabindex", {
3144 value: oAttributes.tabindex,
3145 validator: Lang.isNumber,
3146 method: this._setTabIndex
3153 * @description String specifying the title for the button.
3157 this.configureAttribute("title", {
3159 value: oAttributes.title,
3160 validator: Lang.isString,
3161 method: this._setTitle
3167 * @attribute disabled
3168 * @description Boolean indicating if the button should be disabled.
3169 * (Disabled buttons are dimmed and will not respond to user input
3170 * or fire events. Does not apply to button's of type "link.")
3174 this.setAttributeConfig("disabled", {
3176 value: (oAttributes.disabled || false),
3177 validator: Lang.isBoolean,
3178 method: this._setDisabled
3185 * @description String specifying the href for the button. Applies
3186 * only to buttons of type "link."
3189 this.setAttributeConfig("href", {
3191 value: oAttributes.href,
3192 validator: Lang.isString,
3193 method: this._setHref
3200 * @description String specifying the target for the button.
3201 * Applies only to buttons of type "link."
3204 this.setAttributeConfig("target", {
3206 value: oAttributes.target,
3207 validator: Lang.isString,
3208 method: this._setTarget
3214 * @attribute checked
3215 * @description Boolean indicating if the button is checked.
3216 * Applies only to buttons of type "radio" and "checkbox."
3220 this.setAttributeConfig("checked", {
3222 value: (oAttributes.checked || false),
3223 validator: Lang.isBoolean,
3224 method: this._setChecked
3230 * @attribute container
3231 * @description HTML element reference or string specifying the id
3232 * attribute of the HTML element that the button's markup should be
3234 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3235 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3239 this.setAttributeConfig("container", {
3241 value: oAttributes.container,
3248 * @attribute srcelement
3249 * @description Object reference to the HTML element (either
3250 * <code><input></code> or <code><span></code>)
3251 * used to create the button.
3252 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3253 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3257 this.setAttributeConfig("srcelement", {
3259 value: oAttributes.srcelement,
3267 * @description Object specifying the menu for the button.
3268 * The value can be one of the following:
3270 * <li>Object specifying a <a href="YAHOO.widget.Menu.html">
3271 * YAHOO.widget.Menu</a> instance.</li>
3272 * <li>Object specifying a <a href="YAHOO.widget.Overlay.html">
3273 * YAHOO.widget.Overlay</a> instance.</li>
3274 * <li>String specifying the id attribute of the <code><div>
3275 * </code> element used to create the menu. By default the menu
3276 * will be created as an instance of
3277 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>.
3278 * If the <a href="YAHOO.widget.Menu.html#CSS_CLASS_NAME">
3279 * default CSS class name for YAHOO.widget.Menu</a> is applied to
3280 * the <code><div></code> element, it will be created as an
3281 * instance of <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu
3282 * </a>.</li><li>String specifying the id attribute of the
3283 * <code><select></code> element used to create the menu.
3284 * </li><li>Object specifying the <code><div></code> element
3285 * used to create the menu.</li>
3286 * <li>Object specifying the <code><select></code> element
3287 * used to create the menu.</li>
3288 * <li>Array of object literals, each representing a set of
3289 * <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>
3290 * configuration attributes.</li>
3291 * <li>Array of strings representing the text labels for each menu
3292 * item in the menu.</li>
3294 * @type <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>|<a
3295 * href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|<a
3296 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3297 * one-html.html#ID-58190037">HTMLElement</a>|String|Array
3301 this.setAttributeConfig("menu", {
3304 method: this._setMenu,
3311 * @attribute lazyloadmenu
3312 * @description Boolean indicating the value to set for the
3313 * <a href="YAHOO.widget.Menu.html#lazyLoad">"lazyload"</a>
3314 * configuration property of the button's menu. Setting
3315 * "lazyloadmenu" to <code>true </code> will defer rendering of
3316 * the button's menu until the first time it is made visible.
3317 * If "lazyloadmenu" is set to <code>false</code>, the button's
3318 * menu will be rendered immediately if the button is in the
3319 * document, or in response to the button's "appendTo" event if
3320 * the button is not yet in the document. In either case, the
3321 * menu is rendered into the button's parent HTML element.
3322 * <em>This attribute does not apply if a
3323 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a> or
3324 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
3325 * instance is passed as the value of the button's "menu"
3326 * configuration attribute. <a href="YAHOO.widget.Menu.html">
3327 * YAHOO.widget.Menu</a> or <a href="YAHOO.widget.Overlay.html">
3328 * YAHOO.widget.Overlay</a> instances should be rendered before
3329 * being set as the value for the "menu" configuration
3335 this.setAttributeConfig("lazyloadmenu", {
3337 value: (oAttributes.lazyloadmenu === false ? false : true),
3338 validator: Lang.isBoolean,
3345 * @attribute menuclassname
3346 * @description String representing the CSS class name to be
3347 * applied to the root element of the button's menu.
3349 * @default "yui-button-menu"
3352 this.setAttributeConfig("menuclassname", {
3354 value: (oAttributes.menuclassname || "yui-button-menu"),
3355 validator: Lang.isString,
3356 method: this._setMenuClassName,
3363 * @attribute menuminscrollheight
3364 * @description Number defining the minimum threshold for the "menumaxheight"
3365 * configuration attribute. When set this attribute is automatically applied
3370 this.setAttributeConfig("menuminscrollheight", {
3372 value: (oAttributes.menuminscrollheight || 90),
3373 validator: Lang.isNumber
3379 * @attribute menumaxheight
3380 * @description Number defining the maximum height (in pixels) for a menu's
3381 * body element (<code><div class="bd"<</code>). Once a menu's body
3382 * exceeds this height, the contents of the body are scrolled to maintain
3383 * this value. This value cannot be set lower than the value of the
3384 * "minscrollheight" configuration property.
3388 this.setAttributeConfig("menumaxheight", {
3390 value: (oAttributes.menumaxheight || 0),
3391 validator: Lang.isNumber
3397 * @attribute menualignment
3398 * @description Array defining how the Button's Menu is aligned to the Button.
3399 * The default value of ["tl", "bl"] aligns the Menu's top left corner to the Button's
3400 * bottom left corner.
3402 * @default ["tl", "bl"]
3404 this.setAttributeConfig("menualignment", {
3406 value: (oAttributes.menualignment || ["tl", "bl"]),
3407 validator: Lang.isArray
3413 * @attribute selectedMenuItem
3414 * @description Object representing the item in the button's menu
3415 * that is currently selected.
3419 this.setAttributeConfig("selectedMenuItem", {
3427 * @attribute onclick
3428 * @description Object literal representing the code to be executed
3429 * when the button is clicked. Format:<br> <code> {<br>
3430 * <strong>fn:</strong> Function, // The handler to call
3431 * when the event fires.<br> <strong>obj:</strong> Object,
3432 * // An object to pass back to the handler.<br>
3433 * <strong>scope:</strong> Object // The object to use
3434 * for the scope of the handler.<br> } </code>
3438 this.setAttributeConfig("onclick", {
3440 value: oAttributes.onclick,
3441 method: this._setOnClick
3447 * @attribute focusmenu
3448 * @description Boolean indicating whether or not the button's menu
3449 * should be focused when it is made visible.
3453 this.setAttributeConfig("focusmenu", {
3455 value: (oAttributes.focusmenu === false ? false : true),
3456 validator: Lang.isBoolean
3465 * @description Causes the button to receive the focus and fires the
3466 * button's "focus" event.
3468 focus: function () {
3470 if (!this.get("disabled")) {
3472 this._button.focus();
3481 * @description Causes the button to lose focus and fires the button's
3486 if (!this.get("disabled")) {
3488 this._button.blur();
3497 * @description Returns a boolean indicating whether or not the button
3501 hasFocus: function () {
3503 return (m_oFocusedButton == this);
3510 * @description Returns a boolean indicating whether or not the button
3514 isActive: function () {
3516 return this.hasClass(this.CSS_CLASS_NAME + "-active");
3523 * @description Returns a reference to the button's menu.
3524 * @return {<a href="YAHOO.widget.Overlay.html">
3525 * YAHOO.widget.Overlay</a>|<a
3526 * href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
3528 getMenu: function () {
3537 * @description Returns a reference to the button's parent form.
3538 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-
3539 * 20000929/level-one-html.html#ID-40002357">HTMLFormElement</a>}
3541 getForm: function () {
3543 var oButton = this._button,
3548 oForm = oButton.form;
3558 * @method getHiddenFields
3559 * @description Returns an <code><input></code> element or
3560 * array of form elements used to represent the button when its parent
3561 * form is submitted.
3562 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3563 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
3565 getHiddenFields: function () {
3567 return this._hiddenFields;
3574 * @description Removes the button's element from its parent element and
3575 * removes all event handlers.
3577 destroy: function () {
3580 var oElement = this.get("element"),
3581 oParentNode = oElement.parentNode,
3588 if (m_oOverlayManager && m_oOverlayManager.find(oMenu)) {
3590 m_oOverlayManager.remove(oMenu);
3599 Event.purgeElement(oElement);
3600 Event.purgeElement(this._button);
3601 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
3602 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
3603 Event.removeListener(document, "mousedown", this._onDocumentMouseDown);
3606 var oForm = this.getForm();
3610 Event.removeListener(oForm, "reset", this._onFormReset);
3611 Event.removeListener(oForm, "submit", this._onFormSubmit);
3616 this.unsubscribeAll();
3620 oParentNode.removeChild(oElement);
3625 delete m_oButtons[this.get("id")];
3627 aButtons = Dom.getElementsByClassName(this.CSS_CLASS_NAME,
3628 this.NODE_NAME, oForm);
3630 if (Lang.isArray(aButtons) && aButtons.length === 0) {
3632 Event.removeListener(oForm, "keypress",
3633 YAHOO.widget.Button.onFormKeyPress);
3641 fireEvent: function (p_sType , p_aArgs) {
3643 var sType = arguments[0];
3645 // Disabled buttons should not respond to DOM events
3647 if (this.DOM_EVENTS[sType] && this.get("disabled")) {
3653 return YAHOO.widget.Button.superclass.fireEvent.apply(this, arguments);
3660 * @description Returns a string representing the button.
3663 toString: function () {
3665 return ("Button " + this.get("id"));
3673 * @method YAHOO.widget.Button.onFormKeyPress
3674 * @description "keypress" event handler for the button's form.
3675 * @param {Event} p_oEvent Object representing the DOM event object passed
3676 * back by the event utility (YAHOO.util.Event).
3678 YAHOO.widget.Button.onFormKeyPress = function (p_oEvent) {
3680 var oTarget = Event.getTarget(p_oEvent),
3681 nCharCode = Event.getCharCode(p_oEvent),
3682 sNodeName = oTarget.nodeName && oTarget.nodeName.toUpperCase(),
3683 sType = oTarget.type,
3686 Boolean indicating if the form contains any enabled or
3687 disabled YUI submit buttons
3690 bFormContainsYUIButtons = false,
3694 oYUISubmitButton, // The form's first, enabled YUI submit button
3697 The form's first, enabled HTML submit button that precedes any
3701 oPrecedingSubmitButton,
3706 function isSubmitButton(p_oElement) {
3711 switch (p_oElement.nodeName.toUpperCase()) {
3716 if (p_oElement.type == "submit" && !p_oElement.disabled) {
3718 if (!bFormContainsYUIButtons && !oPrecedingSubmitButton) {
3720 oPrecedingSubmitButton = p_oElement;
3731 sId = p_oElement.id;
3735 oButton = m_oButtons[sId];
3739 bFormContainsYUIButtons = true;
3741 if (!oButton.get("disabled")) {
3743 oSrcElement = oButton.get("srcelement");
3745 if (!oYUISubmitButton && (oButton.get("type") == "submit" ||
3746 (oSrcElement && oSrcElement.type == "submit"))) {
3748 oYUISubmitButton = oButton;
3765 if (nCharCode == 13 && ((sNodeName == "INPUT" && (sType == "text" ||
3766 sType == "password" || sType == "checkbox" || sType == "radio" ||
3767 sType == "file")) || sNodeName == "SELECT")) {
3769 Dom.getElementsBy(isSubmitButton, "*", this);
3772 if (oPrecedingSubmitButton) {
3775 Need to set focus to the first enabled submit button
3776 to make sure that IE includes its name and value
3777 in the form's data set.
3780 oPrecedingSubmitButton.focus();
3783 else if (!oPrecedingSubmitButton && oYUISubmitButton) {
3786 Need to call "preventDefault" to ensure that the form doesn't end up getting
3790 Event.preventDefault(p_oEvent);
3795 oYUISubmitButton.get("element").fireEvent("onclick");
3800 oEvent = document.createEvent("HTMLEvents");
3801 oEvent.initEvent("click", true, true);
3804 if (UA.gecko < 1.9) {
3806 oYUISubmitButton.fireEvent("click", oEvent);
3811 oYUISubmitButton.get("element").dispatchEvent(oEvent);
3825 * @method YAHOO.widget.Button.addHiddenFieldsToForm
3826 * @description Searches the specified form and adds hidden fields for
3827 * instances of YAHOO.widget.Button that are of type "radio," "checkbox,"
3828 * "menu," and "split."
3829 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3830 * one-html.html#ID-40002357">HTMLFormElement</a>} p_oForm Object reference
3831 * for the form to search.
3833 YAHOO.widget.Button.addHiddenFieldsToForm = function (p_oForm) {
3835 var aButtons = Dom.getElementsByClassName(
3836 YAHOO.widget.Button.prototype.CSS_CLASS_NAME,
3840 nButtons = aButtons.length,
3848 for (i = 0; i < nButtons; i++) {
3850 sId = aButtons[i].id;
3854 oButton = m_oButtons[sId];
3858 oButton.createHiddenFields();
3872 * @method YAHOO.widget.Button.getButton
3873 * @description Returns a button with the specified id.
3874 * @param {String} p_sId String specifying the id of the root node of the
3875 * HTML element representing the button to be retrieved.
3876 * @return {YAHOO.widget.Button}
3878 YAHOO.widget.Button.getButton = function (p_sId) {
3880 return m_oButtons[p_sId];
3890 * @description Fires when the menu item receives focus. Passes back a
3891 * single object representing the original DOM event object passed back by
3892 * the event utility (YAHOO.util.Event) when the event was fired. See
3893 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3894 * for more information on listening for this event.
3895 * @type YAHOO.util.CustomEvent
3901 * @description Fires when the menu item loses the input focus. Passes back
3902 * a single object representing the original DOM event object passed back by
3903 * the event utility (YAHOO.util.Event) when the event was fired. See
3904 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for
3905 * more information on listening for this event.
3906 * @type YAHOO.util.CustomEvent
3912 * @description Fires when the user invokes the button's option. Passes
3913 * back a single object representing the original DOM event (either
3914 * "mousedown" or "keydown") that caused the "option" event to fire. See
3915 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3916 * for more information on listening for this event.
3917 * @type YAHOO.util.CustomEvent
3923 // Shorthard for utilities
3925 var Dom = YAHOO.util.Dom,
3926 Event = YAHOO.util.Event,
3928 Button = YAHOO.widget.Button,
3930 // Private collection of radio buttons
3937 * The ButtonGroup class creates a set of buttons that are mutually
3938 * exclusive; checking one button in the set will uncheck all others in the
3940 * @param {String} p_oElement String specifying the id attribute of the
3941 * <code><div></code> element of the button group.
3942 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3943 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
3944 * specifying the <code><div></code> element of the button group.
3945 * @param {Object} p_oElement Object literal specifying a set of
3946 * configuration attributes used to create the button group.
3947 * @param {Object} p_oAttributes Optional. Object literal specifying a set
3948 * of configuration attributes used to create the button group.
3949 * @namespace YAHOO.widget
3950 * @class ButtonGroup
3952 * @extends YAHOO.util.Element
3954 YAHOO.widget.ButtonGroup = function (p_oElement, p_oAttributes) {
3956 var fnSuperClass = YAHOO.widget.ButtonGroup.superclass.constructor,
3961 if (arguments.length == 1 && !Lang.isString(p_oElement) &&
3962 !p_oElement.nodeName) {
3964 if (!p_oElement.id) {
3966 sId = Dom.generateId();
3968 p_oElement.id = sId;
3975 fnSuperClass.call(this, (this._createGroupElement()), p_oElement);
3978 else if (Lang.isString(p_oElement)) {
3980 oElement = Dom.get(p_oElement);
3984 if (oElement.nodeName.toUpperCase() == this.NODE_NAME) {
3987 fnSuperClass.call(this, oElement, p_oAttributes);
3996 sNodeName = p_oElement.nodeName.toUpperCase();
3998 if (sNodeName && sNodeName == this.NODE_NAME) {
4000 if (!p_oElement.id) {
4002 p_oElement.id = Dom.generateId();
4008 fnSuperClass.call(this, p_oElement, p_oAttributes);
4017 YAHOO.extend(YAHOO.widget.ButtonGroup, YAHOO.util.Element, {
4020 // Protected properties
4024 * @property _buttons
4025 * @description Array of buttons in the button group.
4038 * @property NODE_NAME
4039 * @description The name of the tag to be used for the button
4049 * @property CSS_CLASS_NAME
4050 * @description String representing the CSS class(es) to be applied
4051 * to the button group's element.
4052 * @default "yui-buttongroup"
4056 CSS_CLASS_NAME: "yui-buttongroup",
4060 // Protected methods
4064 * @method _createGroupElement
4065 * @description Creates the button group's element.
4067 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4068 * level-one-html.html#ID-22445964">HTMLDivElement</a>}
4070 _createGroupElement: function () {
4072 var oElement = document.createElement(this.NODE_NAME);
4080 // Protected attribute setter methods
4084 * @method _setDisabled
4085 * @description Sets the value of the button groups's
4086 * "disabled" attribute.
4088 * @param {Boolean} p_bDisabled Boolean indicating the value for
4089 * the button group's "disabled" attribute.
4091 _setDisabled: function (p_bDisabled) {
4093 var nButtons = this.getCount(),
4102 this._buttons[i].set("disabled", p_bDisabled);
4113 // Protected event handlers
4117 * @method _onKeyDown
4118 * @description "keydown" event handler for the button group.
4120 * @param {Event} p_oEvent Object representing the DOM event object
4121 * passed back by the event utility (YAHOO.util.Event).
4123 _onKeyDown: function (p_oEvent) {
4125 var oTarget = Event.getTarget(p_oEvent),
4126 nCharCode = Event.getCharCode(p_oEvent),
4127 sId = oTarget.parentNode.parentNode.id,
4128 oButton = m_oButtons[sId],
4132 if (nCharCode == 37 || nCharCode == 38) {
4134 nIndex = (oButton.index === 0) ?
4135 (this._buttons.length - 1) : (oButton.index - 1);
4138 else if (nCharCode == 39 || nCharCode == 40) {
4140 nIndex = (oButton.index === (this._buttons.length - 1)) ?
4141 0 : (oButton.index + 1);
4149 this.getButton(nIndex).focus();
4157 * @method _onAppendTo
4158 * @description "appendTo" event handler for the button group.
4160 * @param {Event} p_oEvent Object representing the event that was fired.
4162 _onAppendTo: function (p_oEvent) {
4164 var aButtons = this._buttons,
4165 nButtons = aButtons.length,
4168 for (i = 0; i < nButtons; i++) {
4170 aButtons[i].appendTo(this.get("element"));
4178 * @method _onButtonCheckedChange
4179 * @description "checkedChange" event handler for each button in the
4182 * @param {Event} p_oEvent Object representing the event that was fired.
4183 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4184 * p_oButton Object representing the button that fired the event.
4186 _onButtonCheckedChange: function (p_oEvent, p_oButton) {
4188 var bChecked = p_oEvent.newValue,
4189 oCheckedButton = this.get("checkedButton");
4191 if (bChecked && oCheckedButton != p_oButton) {
4193 if (oCheckedButton) {
4195 oCheckedButton.set("checked", false, true);
4199 this.set("checkedButton", p_oButton);
4200 this.set("value", p_oButton.get("value"));
4203 else if (oCheckedButton && !oCheckedButton.set("checked")) {
4205 oCheckedButton.set("checked", true, true);
4218 * @description The ButtonGroup class's initialization method.
4219 * @param {String} p_oElement String specifying the id attribute of the
4220 * <code><div></code> element of the button group.
4221 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4222 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
4223 * specifying the <code><div></code> element of the button group.
4224 * @param {Object} p_oElement Object literal specifying a set of
4225 * configuration attributes used to create the button group.
4226 * @param {Object} p_oAttributes Optional. Object literal specifying a
4227 * set of configuration attributes used to create the button group.
4229 init: function (p_oElement, p_oAttributes) {
4233 YAHOO.widget.ButtonGroup.superclass.init.call(this, p_oElement,
4236 this.addClass(this.CSS_CLASS_NAME);
4239 var aButtons = this.getElementsByClassName("yui-radio-button");
4242 if (aButtons.length > 0) {
4245 this.addButtons(aButtons);
4251 function isRadioButton(p_oElement) {
4253 return (p_oElement.type == "radio");
4258 Dom.getElementsBy(isRadioButton, "input", this.get("element"));
4261 if (aButtons.length > 0) {
4264 this.addButtons(aButtons);
4268 this.on("keydown", this._onKeyDown);
4269 this.on("appendTo", this._onAppendTo);
4272 var oContainer = this.get("container");
4276 if (Lang.isString(oContainer)) {
4278 Event.onContentReady(oContainer, function () {
4280 this.appendTo(oContainer);
4287 this.appendTo(oContainer);
4299 * @method initAttributes
4300 * @description Initializes all of the configuration attributes used to
4301 * create the button group.
4302 * @param {Object} p_oAttributes Object literal specifying a set of
4303 * configuration attributes used to create the button group.
4305 initAttributes: function (p_oAttributes) {
4307 var oAttributes = p_oAttributes || {};
4309 YAHOO.widget.ButtonGroup.superclass.initAttributes.call(
4315 * @description String specifying the name for the button group.
4316 * This name will be applied to each button in the button group.
4320 this.setAttributeConfig("name", {
4322 value: oAttributes.name,
4323 validator: Lang.isString
4329 * @attribute disabled
4330 * @description Boolean indicating if the button group should be
4331 * disabled. Disabling the button group will disable each button
4332 * in the button group. Disabled buttons are dimmed and will not
4333 * respond to user input or fire events.
4337 this.setAttributeConfig("disabled", {
4339 value: (oAttributes.disabled || false),
4340 validator: Lang.isBoolean,
4341 method: this._setDisabled
4348 * @description Object specifying the value for the button group.
4352 this.setAttributeConfig("value", {
4354 value: oAttributes.value
4360 * @attribute container
4361 * @description HTML element reference or string specifying the id
4362 * attribute of the HTML element that the button group's markup
4363 * should be rendered into.
4364 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4365 * level-one-html.html#ID-58190037">HTMLElement</a>|String
4369 this.setAttributeConfig("container", {
4371 value: oAttributes.container,
4378 * @attribute checkedButton
4379 * @description Reference for the button in the button group that
4381 * @type {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4384 this.setAttributeConfig("checkedButton", {
4395 * @description Adds the button to the button group.
4396 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4397 * p_oButton Object reference for the <a href="YAHOO.widget.Button.html">
4398 * YAHOO.widget.Button</a> instance to be added to the button group.
4399 * @param {String} p_oButton String specifying the id attribute of the
4400 * <code><input></code> or <code><span></code> element
4401 * to be used to create the button to be added to the button group.
4402 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4403 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="
4404 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
4405 * ID-33759296">HTMLElement</a>} p_oButton Object reference for the
4406 * <code><input></code> or <code><span></code> element
4407 * to be used to create the button to be added to the button group.
4408 * @param {Object} p_oButton Object literal specifying a set of
4409 * <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4410 * configuration attributes used to configure the button to be added to
4412 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4414 addButton: function (p_oButton) {
4424 if (p_oButton instanceof Button &&
4425 p_oButton.get("type") == "radio") {
4427 oButton = p_oButton;
4430 else if (!Lang.isString(p_oButton) && !p_oButton.nodeName) {
4432 p_oButton.type = "radio";
4434 oButton = new Button(p_oButton);
4439 oButton = new Button(p_oButton, { type: "radio" });
4446 nIndex = this._buttons.length;
4447 sButtonName = oButton.get("name");
4448 sGroupName = this.get("name");
4450 oButton.index = nIndex;
4452 this._buttons[nIndex] = oButton;
4453 m_oButtons[oButton.get("id")] = oButton;
4456 if (sButtonName != sGroupName) {
4458 oButton.set("name", sGroupName);
4463 if (this.get("disabled")) {
4465 oButton.set("disabled", true);
4470 if (oButton.get("checked")) {
4472 this.set("checkedButton", oButton);
4477 oButtonElement = oButton.get("element");
4478 oGroupElement = this.get("element");
4480 if (oButtonElement.parentNode != oGroupElement) {
4482 oGroupElement.appendChild(oButtonElement);
4487 oButton.on("checkedChange",
4488 this._onButtonCheckedChange, oButton, this);
4499 * @method addButtons
4500 * @description Adds the array of buttons to the button group.
4501 * @param {Array} p_aButtons Array of <a href="YAHOO.widget.Button.html">
4502 * YAHOO.widget.Button</a> instances to be added
4503 * to the button group.
4504 * @param {Array} p_aButtons Array of strings specifying the id
4505 * attribute of the <code><input></code> or <code><span>
4506 * </code> elements to be used to create the buttons to be added to the
4508 * @param {Array} p_aButtons Array of object references for the
4509 * <code><input></code> or <code><span></code> elements
4510 * to be used to create the buttons to be added to the button group.
4511 * @param {Array} p_aButtons Array of object literals, each containing
4512 * a set of <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4513 * configuration attributes used to configure each button to be added
4514 * to the button group.
4517 addButtons: function (p_aButtons) {
4524 if (Lang.isArray(p_aButtons)) {
4526 nButtons = p_aButtons.length;
4531 for (i = 0; i < nButtons; i++) {
4533 oButton = this.addButton(p_aButtons[i]);
4537 aButtons[aButtons.length] = oButton;
4553 * @method removeButton
4554 * @description Removes the button at the specified index from the
4556 * @param {Number} p_nIndex Number specifying the index of the button
4557 * to be removed from the button group.
4559 removeButton: function (p_nIndex) {
4561 var oButton = this.getButton(p_nIndex),
4568 this._buttons.splice(p_nIndex, 1);
4569 delete m_oButtons[oButton.get("id")];
4571 oButton.removeListener("checkedChange",
4572 this._onButtonCheckedChange);
4577 nButtons = this._buttons.length;
4581 i = this._buttons.length - 1;
4585 this._buttons[i].index = i;
4600 * @description Returns the button at the specified index.
4601 * @param {Number} p_nIndex The index of the button to retrieve from the
4603 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4605 getButton: function (p_nIndex) {
4607 return this._buttons[p_nIndex];
4613 * @method getButtons
4614 * @description Returns an array of the buttons in the button group.
4617 getButtons: function () {
4619 return this._buttons;
4626 * @description Returns the number of buttons in the button group.
4629 getCount: function () {
4631 return this._buttons.length;
4638 * @description Sets focus to the button at the specified index.
4639 * @param {Number} p_nIndex Number indicating the index of the button
4642 focus: function (p_nIndex) {
4648 if (Lang.isNumber(p_nIndex)) {
4650 oButton = this._buttons[p_nIndex];
4661 nButtons = this.getCount();
4663 for (i = 0; i < nButtons; i++) {
4665 oButton = this._buttons[i];
4667 if (!oButton.get("disabled")) {
4683 * @description Checks the button at the specified index.
4684 * @param {Number} p_nIndex Number indicating the index of the button
4687 check: function (p_nIndex) {
4689 var oButton = this.getButton(p_nIndex);
4693 oButton.set("checked", true);
4702 * @description Removes the button group's element from its parent
4703 * element and removes all event handlers.
4705 destroy: function () {
4708 var nButtons = this._buttons.length,
4709 oElement = this.get("element"),
4710 oParentNode = oElement.parentNode,
4715 i = this._buttons.length - 1;
4719 this._buttons[i].destroy();
4727 Event.purgeElement(oElement);
4730 oParentNode.removeChild(oElement);
4737 * @description Returns a string representing the button group.
4740 toString: function () {
4742 return ("ButtonGroup " + this.get("id"));
4749 YAHOO.register("button", YAHOO.widget.Button, {version: "2.7.0", build: "1799"});