2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
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)) {
124 if (UA.ie && (UA.ie < 9)) {
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);
145 oInput.value = p_sValue;
149 oInput = document.createElement("input");
150 oInput.name = p_sName;
151 oInput.type = p_sType;
152 oInput.value = p_sValue;
156 oInput.checked = true;
171 * @method setAttributesFromSrcElement
172 * @description Gets the values for all the attributes of the source element
173 * (either <code><input></code> or <code><a></code>) that
174 * map to Button configuration attributes and sets them into a collection
175 * that is passed to the Button constructor.
177 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
178 * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org/
179 * TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-
180 * 48250443">HTMLAnchorElement</a>} p_oElement Object reference to the HTML
181 * element (either <code><input></code> or <code><span>
182 * </code>) used to create the button.
183 * @param {Object} p_oAttributes Object reference for the collection of
184 * configuration attributes used to create the button.
186 function setAttributesFromSrcElement(p_oElement, p_oAttributes) {
188 var sSrcElementNodeName = p_oElement.nodeName.toUpperCase(),
189 sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME),
197 * @method setAttributeFromDOMAttribute
198 * @description Gets the value of the specified DOM attribute and sets it
199 * into the collection of configuration attributes used to configure
202 * @param {String} p_sAttribute String representing the name of the
203 * attribute to retrieve from the DOM element.
205 function setAttributeFromDOMAttribute(p_sAttribute) {
207 if (!(p_sAttribute in p_oAttributes)) {
210 Need to use "getAttributeNode" instead of "getAttribute"
211 because using "getAttribute," IE will return the innerText
212 of a <code><button></code> for the value attribute
213 rather than the value of the "value" attribute.
216 oAttribute = p_oElement.getAttributeNode(p_sAttribute);
219 if (oAttribute && ("value" in oAttribute)) {
222 p_oAttributes[p_sAttribute] = oAttribute.value;
232 * @method setFormElementProperties
233 * @description Gets the value of the attributes from the form element
234 * and sets them into the collection of configuration attributes used to
235 * configure the button.
238 function setFormElementProperties() {
240 setAttributeFromDOMAttribute("type");
242 if (p_oAttributes.type == "button") {
244 p_oAttributes.type = "push";
248 if (!("disabled" in p_oAttributes)) {
250 p_oAttributes.disabled = p_oElement.disabled;
254 setAttributeFromDOMAttribute("name");
255 setAttributeFromDOMAttribute("value");
256 setAttributeFromDOMAttribute("title");
261 switch (sSrcElementNodeName) {
265 p_oAttributes.type = "link";
267 setAttributeFromDOMAttribute("href");
268 setAttributeFromDOMAttribute("target");
274 setFormElementProperties();
276 if (!("checked" in p_oAttributes)) {
278 p_oAttributes.checked = p_oElement.checked;
286 setFormElementProperties();
288 oRootNode = p_oElement.parentNode.parentNode;
290 if (Dom.hasClass(oRootNode, sClass + "-checked")) {
292 p_oAttributes.checked = true;
296 if (Dom.hasClass(oRootNode, sClass + "-disabled")) {
298 p_oAttributes.disabled = true;
302 p_oElement.removeAttribute("value");
304 p_oElement.setAttribute("type", "button");
310 p_oElement.removeAttribute("id");
311 p_oElement.removeAttribute("name");
313 if (!("tabindex" in p_oAttributes)) {
315 p_oAttributes.tabindex = p_oElement.tabIndex;
319 if (!("label" in p_oAttributes)) {
321 // Set the "label" property
323 sText = sSrcElementNodeName == "INPUT" ?
324 p_oElement.value : p_oElement.innerHTML;
327 if (sText && sText.length > 0) {
329 p_oAttributes.label = sText;
340 * @description Initializes the set of configuration attributes that are
341 * used to instantiate the button.
343 * @param {Object} Object representing the button's set of
344 * configuration attributes.
346 function initConfig(p_oConfig) {
348 var oAttributes = p_oConfig.attributes,
349 oSrcElement = oAttributes.srcelement,
350 sSrcElementNodeName = oSrcElement.nodeName.toUpperCase(),
354 if (sSrcElementNodeName == this.NODE_NAME) {
356 p_oConfig.element = oSrcElement;
357 p_oConfig.id = oSrcElement.id;
359 Dom.getElementsBy(function (p_oElement) {
361 switch (p_oElement.nodeName.toUpperCase()) {
367 setAttributesFromSrcElement.call(me, p_oElement,
374 }, "*", oSrcElement);
379 switch (sSrcElementNodeName) {
385 setAttributesFromSrcElement.call(this, oSrcElement,
400 YAHOO.widget.Button = function (p_oElement, p_oAttributes) {
402 if (!Overlay && YAHOO.widget.Overlay) {
404 Overlay = YAHOO.widget.Overlay;
409 if (!Menu && YAHOO.widget.Menu) {
411 Menu = YAHOO.widget.Menu;
416 var fnSuperClass = YAHOO.widget.Button.superclass.constructor,
421 if (arguments.length == 1 && !Lang.isString(p_oElement) && !p_oElement.nodeName) {
423 if (!p_oElement.id) {
425 p_oElement.id = Dom.generateId();
431 fnSuperClass.call(this, (this.createButtonElement(p_oElement.type)), p_oElement);
436 oConfig = { element: null, attributes: (p_oAttributes || {}) };
439 if (Lang.isString(p_oElement)) {
441 oElement = Dom.get(p_oElement);
445 if (!oConfig.attributes.id) {
447 oConfig.attributes.id = p_oElement;
453 oConfig.attributes.srcelement = oElement;
455 initConfig.call(this, oConfig);
458 if (!oConfig.element) {
461 oConfig.element = this.createButtonElement(oConfig.attributes.type);
465 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
470 else if (p_oElement.nodeName) {
472 if (!oConfig.attributes.id) {
476 oConfig.attributes.id = p_oElement.id;
481 oConfig.attributes.id = Dom.generateId();
490 oConfig.attributes.srcelement = p_oElement;
492 initConfig.call(this, oConfig);
495 if (!oConfig.element) {
498 oConfig.element = this.createButtonElement(oConfig.attributes.type);
502 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
512 YAHOO.extend(YAHOO.widget.Button, YAHOO.util.Element, {
515 // Protected properties
520 * @description Object reference to the button's internal
521 * <code><a></code> or <code><button></code> element.
524 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
525 * level-one-html.html#ID-48250443">HTMLAnchorElement</a>|<a href="
526 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
527 * #ID-34812697">HTMLButtonElement</a>
534 * @description Object reference to the button's menu.
537 * @type {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|
538 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
544 * @property _hiddenFields
545 * @description Object reference to the <code><input></code>
546 * element, or array of HTML form elements used to represent the button
547 * when its parent form is submitted.
550 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
551 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array
557 * @property _onclickAttributeValue
558 * @description Object reference to the button's current value for the
559 * "onclick" configuration attribute.
564 _onclickAttributeValue: null,
568 * @property _activationKeyPressed
569 * @description Boolean indicating if the key(s) that toggle the button's
570 * "active" state have been pressed.
575 _activationKeyPressed: false,
579 * @property _activationButtonPressed
580 * @description Boolean indicating if the mouse button that toggles
581 * the button's "active" state has been pressed.
586 _activationButtonPressed: false,
590 * @property _hasKeyEventHandlers
591 * @description Boolean indicating if the button's "blur", "keydown" and
592 * "keyup" event handlers are assigned
597 _hasKeyEventHandlers: false,
601 * @property _hasMouseEventHandlers
602 * @description Boolean indicating if the button's "mouseout,"
603 * "mousedown," and "mouseup" event handlers are assigned
608 _hasMouseEventHandlers: false,
612 * @property _nOptionRegionX
613 * @description Number representing the X coordinate of the leftmost edge of the Button's
614 * option region. Applies only to Buttons of type "split".
626 * @property CLASS_NAME_PREFIX
627 * @description Prefix used for all class names applied to a Button.
632 CLASS_NAME_PREFIX: "yui-",
636 * @property NODE_NAME
637 * @description The name of the node to be used for the button's
647 * @property CHECK_ACTIVATION_KEYS
648 * @description Array of numbers representing keys that (when pressed)
649 * toggle the button's "checked" attribute.
654 CHECK_ACTIVATION_KEYS: [32],
658 * @property ACTIVATION_KEYS
659 * @description Array of numbers representing keys that (when presed)
660 * toggle the button's "active" state.
665 ACTIVATION_KEYS: [13, 32],
669 * @property OPTION_AREA_WIDTH
670 * @description Width (in pixels) of the area of a split button that
671 * when pressed will display a menu.
676 OPTION_AREA_WIDTH: 20,
680 * @property CSS_CLASS_NAME
681 * @description String representing the CSS class(es) to be applied to
682 * the button's root element.
687 CSS_CLASS_NAME: "button",
691 // Protected attribute setter methods
696 * @description Sets the value of the button's "type" attribute.
698 * @param {String} p_sType String indicating the value for the button's
701 _setType: function (p_sType) {
703 if (p_sType == "split") {
705 this.on("option", this._onOption);
714 * @description Sets the value of the button's "label" attribute.
716 * @param {HTML} p_sLabel String indicating the value for the button's
719 _setLabel: function (p_sLabel) {
721 this._button.innerHTML = p_sLabel;
725 Remove and add the default class name from the root element
726 for Gecko to ensure that the button shrinkwraps to the label.
727 Without this the button will not be rendered at the correct
728 width when the label changes. The most likely cause for this
729 bug is button's use of the Gecko-specific CSS display type of
730 "-moz-inline-box" to simulate "inline-block" supported by IE,
735 nGeckoVersion = UA.gecko;
738 if (nGeckoVersion && nGeckoVersion < 1.9 && Dom.inDocument(this.get("element"))) {
740 sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME);
742 this.removeClass(sClass);
744 Lang.later(0, this, this.addClass, sClass);
752 * @method _setTabIndex
753 * @description Sets the value of the button's "tabindex" attribute.
755 * @param {Number} p_nTabIndex Number indicating the value for the
756 * button's "tabindex" attribute.
758 _setTabIndex: function (p_nTabIndex) {
760 this._button.tabIndex = p_nTabIndex;
767 * @description Sets the value of the button's "title" attribute.
769 * @param {String} p_nTabIndex Number indicating the value for
770 * the button's "title" attribute.
772 _setTitle: function (p_sTitle) {
774 if (this.get("type") != "link") {
776 this._button.title = p_sTitle;
784 * @method _setDisabled
785 * @description Sets the value of the button's "disabled" attribute.
787 * @param {Boolean} p_bDisabled Boolean indicating the value for
788 * the button's "disabled" attribute.
790 _setDisabled: function (p_bDisabled) {
792 if (this.get("type") != "link") {
802 if (this.hasFocus()) {
808 this._button.setAttribute("disabled", "disabled");
810 this.addStateCSSClasses("disabled");
812 this.removeStateCSSClasses("hover");
813 this.removeStateCSSClasses("active");
814 this.removeStateCSSClasses("focus");
819 this._button.removeAttribute("disabled");
821 this.removeStateCSSClasses("disabled");
832 * @description Sets the value of the button's "href" attribute.
834 * @param {String} p_sHref String indicating the value for the button's
837 _setHref: function (p_sHref) {
839 if (this.get("type") == "link") {
841 this._button.href = p_sHref;
850 * @description Sets the value of the button's "target" attribute.
852 * @param {String} p_sTarget String indicating the value for the button's
853 * "target" attribute.
855 _setTarget: function (p_sTarget) {
857 if (this.get("type") == "link") {
859 this._button.setAttribute("target", p_sTarget);
867 * @method _setChecked
868 * @description Sets the value of the button's "target" attribute.
870 * @param {Boolean} p_bChecked Boolean indicating the value for
871 * the button's "checked" attribute.
873 _setChecked: function (p_bChecked) {
875 var sType = this.get("type");
877 if (sType == "checkbox" || sType == "radio") {
880 this.addStateCSSClasses("checked");
883 this.removeStateCSSClasses("checked");
893 * @description Sets the value of the button's "menu" attribute.
895 * @param {Object} p_oMenu Object indicating the value for the button's
898 _setMenu: function (p_oMenu) {
900 var bLazyLoad = this.get("lazyloadmenu"),
901 oButtonElement = this.get("element"),
905 Boolean indicating if the value of p_oMenu is an instance
906 of YAHOO.widget.Menu or YAHOO.widget.Overlay.
915 function onAppendTo() {
917 oMenu.render(oButtonElement.parentNode);
919 this.removeListener("appendTo", onAppendTo);
924 function setMenuContainer() {
926 oMenu.cfg.queueProperty("container", oButtonElement.parentNode);
928 this.removeListener("appendTo", setMenuContainer);
933 function initMenu() {
939 Dom.addClass(oMenu.element, this.get("menuclassname"));
940 Dom.addClass(oMenu.element, this.CLASS_NAME_PREFIX + this.get("type") + "-button-menu");
942 oMenu.showEvent.subscribe(this._onMenuShow, null, this);
943 oMenu.hideEvent.subscribe(this._onMenuHide, null, this);
944 oMenu.renderEvent.subscribe(this._onMenuRender, null, this);
947 if (Menu && oMenu instanceof Menu) {
951 oContainer = this.get("container");
955 oMenu.cfg.queueProperty("container", oContainer);
960 this.on("appendTo", setMenuContainer);
966 oMenu.cfg.queueProperty("clicktohide", false);
968 oMenu.keyDownEvent.subscribe(this._onMenuKeyDown, this, true);
969 oMenu.subscribe("click", this._onMenuClick, this, true);
971 this.on("selectedMenuItemChange", this._onSelectedMenuItemChange);
973 oSrcElement = oMenu.srcElement;
975 if (oSrcElement && oSrcElement.nodeName.toUpperCase() == "SELECT") {
977 oSrcElement.style.display = "none";
978 oSrcElement.parentNode.removeChild(oSrcElement);
983 else if (Overlay && oMenu instanceof Overlay) {
985 if (!m_oOverlayManager) {
987 m_oOverlayManager = new YAHOO.widget.OverlayManager();
991 m_oOverlayManager.register(oMenu);
999 if (!bInstance && !bLazyLoad) {
1001 if (Dom.inDocument(oButtonElement)) {
1003 oMenu.render(oButtonElement.parentNode);
1008 this.on("appendTo", onAppendTo);
1023 sMenuCSSClassName = Menu.prototype.CSS_CLASS_NAME;
1027 if (p_oMenu && Menu && (p_oMenu instanceof Menu)) {
1032 initMenu.call(this);
1035 else if (Overlay && p_oMenu && (p_oMenu instanceof Overlay)) {
1040 oMenu.cfg.queueProperty("visible", false);
1042 initMenu.call(this);
1045 else if (Menu && Lang.isArray(p_oMenu)) {
1047 oMenu = new Menu(Dom.generateId(), { lazyload: bLazyLoad, itemdata: p_oMenu });
1051 this.on("appendTo", initMenu);
1054 else if (Lang.isString(p_oMenu)) {
1056 oMenuElement = Dom.get(p_oMenu);
1060 if (Menu && Dom.hasClass(oMenuElement, sMenuCSSClassName) ||
1061 oMenuElement.nodeName.toUpperCase() == "SELECT") {
1063 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1065 initMenu.call(this);
1070 oMenu = new Overlay(p_oMenu, { visible: false });
1072 initMenu.call(this);
1079 else if (p_oMenu && p_oMenu.nodeName) {
1081 if (Menu && Dom.hasClass(p_oMenu, sMenuCSSClassName) ||
1082 p_oMenu.nodeName.toUpperCase() == "SELECT") {
1084 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1086 initMenu.call(this);
1093 Dom.generateId(p_oMenu);
1097 oMenu = new Overlay(p_oMenu, { visible: false });
1099 initMenu.call(this);
1111 * @method _setOnClick
1112 * @description Sets the value of the button's "onclick" attribute.
1114 * @param {Object} p_oObject Object indicating the value for the button's
1115 * "onclick" attribute.
1117 _setOnClick: function (p_oObject) {
1120 Remove any existing listeners if a "click" event handler
1121 has already been specified.
1124 if (this._onclickAttributeValue &&
1125 (this._onclickAttributeValue != p_oObject)) {
1127 this.removeListener("click", this._onclickAttributeValue.fn);
1129 this._onclickAttributeValue = null;
1134 if (!this._onclickAttributeValue &&
1135 Lang.isObject(p_oObject) &&
1136 Lang.isFunction(p_oObject.fn)) {
1138 this.on("click", p_oObject.fn, p_oObject.obj, p_oObject.scope);
1140 this._onclickAttributeValue = p_oObject;
1148 // Protected methods
1153 * @method _isActivationKey
1154 * @description Determines if the specified keycode is one that toggles
1155 * the button's "active" state.
1157 * @param {Number} p_nKeyCode Number representing the keycode to
1161 _isActivationKey: function (p_nKeyCode) {
1163 var sType = this.get("type"),
1164 aKeyCodes = (sType == "checkbox" || sType == "radio") ?
1165 this.CHECK_ACTIVATION_KEYS : this.ACTIVATION_KEYS,
1167 nKeyCodes = aKeyCodes.length,
1172 if (nKeyCodes > 0) {
1178 if (p_nKeyCode == aKeyCodes[i]) {
1196 * @method _isSplitButtonOptionKey
1197 * @description Determines if the specified keycode is one that toggles
1198 * the display of the split button's menu.
1200 * @param {Event} p_oEvent Object representing the DOM event object
1201 * passed back by the event utility (YAHOO.util.Event).
1204 _isSplitButtonOptionKey: function (p_oEvent) {
1206 var bShowMenu = (Event.getCharCode(p_oEvent) == 40);
1209 var onKeyPress = function (p_oEvent) {
1211 Event.preventDefault(p_oEvent);
1213 this.removeListener("keypress", onKeyPress);
1218 // Prevent the browser from scrolling the window
1223 this.on("keypress", onKeyPress);
1227 Event.preventDefault(p_oEvent);
1236 * @method _addListenersToForm
1237 * @description Adds event handlers to the button's form.
1240 _addListenersToForm: function () {
1242 var oForm = this.getForm(),
1243 onFormKeyPress = YAHOO.widget.Button.onFormKeyPress,
1244 bHasKeyPressListener,
1253 Event.on(oForm, "reset", this._onFormReset, null, this);
1254 Event.on(oForm, "submit", this._onFormSubmit, null, this);
1256 oSrcElement = this.get("srcelement");
1259 if (this.get("type") == "submit" ||
1260 (oSrcElement && oSrcElement.type == "submit"))
1263 aListeners = Event.getListeners(oForm, "keypress");
1264 bHasKeyPressListener = false;
1268 nListeners = aListeners.length;
1270 if (nListeners > 0) {
1276 if (aListeners[i].fn == onFormKeyPress) {
1278 bHasKeyPressListener = true;
1291 if (!bHasKeyPressListener) {
1293 Event.on(oForm, "keypress", onFormKeyPress);
1307 * @description Shows the button's menu.
1309 * @param {Event} p_oEvent Object representing the DOM event object
1310 * passed back by the event utility (YAHOO.util.Event) that triggered
1311 * the display of the menu.
1313 _showMenu: function (p_oEvent) {
1315 if (YAHOO.widget.MenuManager) {
1316 YAHOO.widget.MenuManager.hideVisible();
1320 if (m_oOverlayManager) {
1321 m_oOverlayManager.hideAll();
1325 var oMenu = this._menu,
1326 aMenuAlignment = this.get("menualignment"),
1327 bFocusMenu = this.get("focusmenu"),
1331 if (this._renderedMenu) {
1333 oMenu.cfg.setProperty("context",
1334 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1336 oMenu.cfg.setProperty("preventcontextoverlap", true);
1337 oMenu.cfg.setProperty("constraintoviewport", true);
1342 oMenu.cfg.queueProperty("context",
1343 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1345 oMenu.cfg.queueProperty("preventcontextoverlap", true);
1346 oMenu.cfg.queueProperty("constraintoviewport", true);
1352 Refocus the Button before showing its Menu in case the call to
1353 YAHOO.widget.MenuManager.hideVisible() resulted in another element in the
1354 DOM being focused after another Menu was hidden.
1360 if (Menu && oMenu && (oMenu instanceof Menu)) {
1362 // Since Menus automatically focus themselves when made visible, temporarily
1363 // replace the Menu focus method so that the value of the Button's "focusmenu"
1364 // attribute determines if the Menu should be focus when made visible.
1366 fnFocusMethod = oMenu.focus;
1368 oMenu.focus = function () {};
1370 if (this._renderedMenu) {
1372 oMenu.cfg.setProperty("minscrollheight", this.get("menuminscrollheight"));
1373 oMenu.cfg.setProperty("maxheight", this.get("menumaxheight"));
1378 oMenu.cfg.queueProperty("minscrollheight", this.get("menuminscrollheight"));
1379 oMenu.cfg.queueProperty("maxheight", this.get("menumaxheight"));
1386 oMenu.focus = fnFocusMethod;
1392 Stop the propagation of the event so that the MenuManager
1393 doesn't blur the menu after it gets focus.
1396 if (p_oEvent.type == "mousedown") {
1397 Event.stopPropagation(p_oEvent);
1406 else if (Overlay && oMenu && (oMenu instanceof Overlay)) {
1408 if (!this._renderedMenu) {
1409 oMenu.render(this.get("element").parentNode);
1422 * @description Hides the button's menu.
1425 _hideMenu: function () {
1427 var oMenu = this._menu;
1440 // Protected event handlers
1444 * @method _onMouseOver
1445 * @description "mouseover" event handler for the button.
1447 * @param {Event} p_oEvent Object representing the DOM event object
1448 * passed back by the event utility (YAHOO.util.Event).
1450 _onMouseOver: function (p_oEvent) {
1452 var sType = this.get("type"),
1457 if (sType === "split") {
1459 oElement = this.get("element");
1461 (Dom.getX(oElement) + (oElement.offsetWidth - this.OPTION_AREA_WIDTH));
1463 this._nOptionRegionX = nOptionRegionX;
1468 if (!this._hasMouseEventHandlers) {
1470 if (sType === "split") {
1472 this.on("mousemove", this._onMouseMove);
1476 this.on("mouseout", this._onMouseOut);
1478 this._hasMouseEventHandlers = true;
1483 this.addStateCSSClasses("hover");
1486 if (sType === "split" && (Event.getPageX(p_oEvent) > nOptionRegionX)) {
1488 this.addStateCSSClasses("hoveroption");
1493 if (this._activationButtonPressed) {
1495 this.addStateCSSClasses("active");
1500 if (this._bOptionPressed) {
1502 this.addStateCSSClasses("activeoption");
1507 if (this._activationButtonPressed || this._bOptionPressed) {
1509 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1517 * @method _onMouseMove
1518 * @description "mousemove" event handler for the button.
1520 * @param {Event} p_oEvent Object representing the DOM event object
1521 * passed back by the event utility (YAHOO.util.Event).
1523 _onMouseMove: function (p_oEvent) {
1525 var nOptionRegionX = this._nOptionRegionX;
1527 if (nOptionRegionX) {
1529 if (Event.getPageX(p_oEvent) > nOptionRegionX) {
1531 this.addStateCSSClasses("hoveroption");
1536 this.removeStateCSSClasses("hoveroption");
1545 * @method _onMouseOut
1546 * @description "mouseout" event handler for the button.
1548 * @param {Event} p_oEvent Object representing the DOM event object
1549 * passed back by the event utility (YAHOO.util.Event).
1551 _onMouseOut: function (p_oEvent) {
1553 var sType = this.get("type");
1555 this.removeStateCSSClasses("hover");
1558 if (sType != "menu") {
1560 this.removeStateCSSClasses("active");
1565 if (this._activationButtonPressed || this._bOptionPressed) {
1567 Event.on(document, "mouseup", this._onDocumentMouseUp, null, this);
1572 if (sType === "split" && (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
1574 this.removeStateCSSClasses("hoveroption");
1582 * @method _onDocumentMouseUp
1583 * @description "mouseup" event handler for the button.
1585 * @param {Event} p_oEvent Object representing the DOM event object
1586 * passed back by the event utility (YAHOO.util.Event).
1588 _onDocumentMouseUp: function (p_oEvent) {
1590 this._activationButtonPressed = false;
1591 this._bOptionPressed = false;
1593 var sType = this.get("type"),
1597 if (sType == "menu" || sType == "split") {
1599 oTarget = Event.getTarget(p_oEvent);
1600 oMenuElement = this._menu.element;
1602 if (oTarget != oMenuElement &&
1603 !Dom.isAncestor(oMenuElement, oTarget)) {
1605 this.removeStateCSSClasses((sType == "menu" ?
1606 "active" : "activeoption"));
1614 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1620 * @method _onMouseDown
1621 * @description "mousedown" event handler for the button.
1623 * @param {Event} p_oEvent Object representing the DOM event object
1624 * passed back by the event utility (YAHOO.util.Event).
1626 _onMouseDown: function (p_oEvent) {
1632 function onMouseUp() {
1635 this.removeListener("mouseup", onMouseUp);
1640 if ((p_oEvent.which || p_oEvent.button) == 1) {
1643 if (!this.hasFocus()) {
1644 Lang.later(0, this, this.focus);
1649 sType = this.get("type");
1652 if (sType == "split") {
1654 if (Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1656 this.fireEvent("option", p_oEvent);
1662 this.addStateCSSClasses("active");
1664 this._activationButtonPressed = true;
1669 else if (sType == "menu") {
1671 if (this.isActive()) {
1675 this._activationButtonPressed = false;
1680 this._showMenu(p_oEvent);
1682 this._activationButtonPressed = true;
1689 this.addStateCSSClasses("active");
1691 this._activationButtonPressed = true;
1697 if (sType == "split" || sType == "menu") {
1699 this._hideMenuTimer = Lang.later(250, this, this.on, ["mouseup", onMouseUp]);
1711 * @method _onMouseUp
1712 * @description "mouseup" event handler for the button.
1714 * @param {Event} p_oEvent Object representing the DOM event object
1715 * passed back by the event utility (YAHOO.util.Event).
1717 _onMouseUp: function (p_oEvent) {
1718 this.inMouseDown = false;
1720 var sType = this.get("type"),
1721 oHideMenuTimer = this._hideMenuTimer,
1725 if (oHideMenuTimer) {
1727 oHideMenuTimer.cancel();
1732 if (sType == "checkbox" || sType == "radio") {
1733 if ((p_oEvent.which || p_oEvent.button) != 1) {
1737 this.set("checked", !(this.get("checked")));
1742 this._activationButtonPressed = false;
1745 if (sType != "menu") {
1747 this.removeStateCSSClasses("active");
1752 if (sType == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1765 * @description "focus" event handler for the button.
1767 * @param {Event} p_oEvent Object representing the DOM event object
1768 * passed back by the event utility (YAHOO.util.Event).
1770 _onFocus: function (p_oEvent) {
1774 this.addStateCSSClasses("focus");
1776 if (this._activationKeyPressed) {
1778 this.addStateCSSClasses("active");
1782 m_oFocusedButton = this;
1785 if (!this._hasKeyEventHandlers) {
1787 oElement = this._button;
1789 Event.on(oElement, "blur", this._onBlur, null, this);
1790 Event.on(oElement, "keydown", this._onKeyDown, null, this);
1791 Event.on(oElement, "keyup", this._onKeyUp, null, this);
1793 this._hasKeyEventHandlers = true;
1798 this.fireEvent("focus", p_oEvent);
1805 * @description "blur" event handler for the button.
1807 * @param {Event} p_oEvent Object representing the DOM event object
1808 * passed back by the event utility (YAHOO.util.Event).
1810 _onBlur: function (p_oEvent) {
1812 this.removeStateCSSClasses("focus");
1814 if (this.get("type") != "menu") {
1816 this.removeStateCSSClasses("active");
1820 if (this._activationKeyPressed) {
1822 Event.on(document, "keyup", this._onDocumentKeyUp, null, this);
1827 m_oFocusedButton = null;
1829 this.fireEvent("blur", p_oEvent);
1835 * @method _onDocumentKeyUp
1836 * @description "keyup" event handler for the document.
1838 * @param {Event} p_oEvent Object representing the DOM event object
1839 * passed back by the event utility (YAHOO.util.Event).
1841 _onDocumentKeyUp: function (p_oEvent) {
1843 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1845 this._activationKeyPressed = false;
1847 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
1855 * @method _onKeyDown
1856 * @description "keydown" event handler for the button.
1858 * @param {Event} p_oEvent Object representing the DOM event object
1859 * passed back by the event utility (YAHOO.util.Event).
1861 _onKeyDown: function (p_oEvent) {
1863 var oMenu = this._menu;
1866 if (this.get("type") == "split" &&
1867 this._isSplitButtonOptionKey(p_oEvent)) {
1869 this.fireEvent("option", p_oEvent);
1872 else if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1874 if (this.get("type") == "menu") {
1876 this._showMenu(p_oEvent);
1881 this._activationKeyPressed = true;
1883 this.addStateCSSClasses("active");
1890 if (oMenu && oMenu.cfg.getProperty("visible") &&
1891 Event.getCharCode(p_oEvent) == 27) {
1903 * @description "keyup" event handler for the button.
1905 * @param {Event} p_oEvent Object representing the DOM event object
1906 * passed back by the event utility (YAHOO.util.Event).
1908 _onKeyUp: function (p_oEvent) {
1912 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1914 sType = this.get("type");
1916 if (sType == "checkbox" || sType == "radio") {
1918 this.set("checked", !(this.get("checked")));
1922 this._activationKeyPressed = false;
1924 if (this.get("type") != "menu") {
1926 this.removeStateCSSClasses("active");
1937 * @description "click" event handler for the button.
1939 * @param {Event} p_oEvent Object representing the DOM event object
1940 * passed back by the event utility (YAHOO.util.Event).
1942 _onClick: function (p_oEvent) {
1944 var sType = this.get("type"),
1954 if (p_oEvent.returnValue !== false) {
1964 oForm = this.getForm();
1977 if (this._nOptionRegionX > 0 &&
1978 (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
1987 oSrcElement = this.get("srcelement");
1989 if (oSrcElement && oSrcElement.type == "submit" &&
1990 p_oEvent.returnValue !== false) {
2008 * @method _onDblClick
2009 * @description "dblclick" event handler for the button.
2011 * @param {Event} p_oEvent Object representing the DOM event object
2012 * passed back by the event utility (YAHOO.util.Event).
2014 _onDblClick: function (p_oEvent) {
2016 var bReturnVal = true;
2018 if (this.get("type") == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
2030 * @method _onAppendTo
2031 * @description "appendTo" event handler for the button.
2033 * @param {Event} p_oEvent Object representing the DOM event object
2034 * passed back by the event utility (YAHOO.util.Event).
2036 _onAppendTo: function (p_oEvent) {
2039 It is necessary to call "_addListenersToForm" using
2040 "setTimeout" to make sure that the button's "form" property
2041 returns a node reference. Sometimes, if you try to get the
2042 reference immediately after appending the field, it is null.
2045 Lang.later(0, this, this._addListenersToForm);
2051 * @method _onFormReset
2052 * @description "reset" event handler for the button's form.
2054 * @param {Event} p_oEvent Object representing the DOM event
2055 * object passed back by the event utility (YAHOO.util.Event).
2057 _onFormReset: function (p_oEvent) {
2059 var sType = this.get("type"),
2062 if (sType == "checkbox" || sType == "radio") {
2064 this.resetValue("checked");
2069 if (Menu && oMenu && (oMenu instanceof Menu)) {
2071 this.resetValue("selectedMenuItem");
2079 * @method _onFormSubmit
2080 * @description "submit" event handler for the button's form.
2082 * @param {Event} p_oEvent Object representing the DOM event
2083 * object passed back by the event utility (YAHOO.util.Event).
2085 _onFormSubmit: function (p_oEvent) {
2087 this.createHiddenFields();
2093 * @method _onDocumentMouseDown
2094 * @description "mousedown" event handler for the document.
2096 * @param {Event} p_oEvent Object representing the DOM event object
2097 * passed back by the event utility (YAHOO.util.Event).
2099 _onDocumentMouseDown: function (p_oEvent) {
2101 var oTarget = Event.getTarget(p_oEvent),
2102 oButtonElement = this.get("element"),
2103 oMenuElement = this._menu.element;
2105 function findTargetInSubmenus(aSubmenus) {
2106 var i, iMax, oSubmenuElement;
2110 for (i = 0, iMax = aSubmenus.length; i < iMax; i++) {
2111 oSubmenuElement = aSubmenus[i].element;
2112 if (oTarget == oSubmenuElement || Dom.isAncestor(oSubmenuElement, oTarget)) {
2115 if (aSubmenus[i] && aSubmenus[i].getSubmenus) {
2116 if (findTargetInSubmenus(aSubmenus[i].getSubmenus())) {
2125 if (oTarget != oButtonElement &&
2126 !Dom.isAncestor(oButtonElement, oTarget) &&
2127 oTarget != oMenuElement &&
2128 !Dom.isAncestor(oMenuElement, oTarget)) {
2131 if (this._menu && this._menu.getSubmenus) {
2132 if (!findTargetInSubmenus(this._menu.getSubmenus())) {
2140 // In IE when the user mouses down on a focusable element
2141 // that element will be focused and become the "activeElement".
2142 // (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
2143 // However, there is a bug in IE where if there is a
2144 // positioned element with a focused descendant that is
2145 // hidden in response to the mousedown event, the target of
2146 // the mousedown event will appear to have focus, but will
2147 // not be set as the activeElement. This will result
2148 // in the element not firing key events, even though it
2149 // appears to have focus. The following call to "setActive"
2152 if (UA.ie && (UA.ie < 9) && oTarget.focus) {
2153 oTarget.setActive();
2156 Event.removeListener(document, "mousedown",
2157 this._onDocumentMouseDown);
2166 * @description "option" event handler for the button.
2168 * @param {Event} p_oEvent Object representing the DOM event object
2169 * passed back by the event utility (YAHOO.util.Event).
2171 _onOption: function (p_oEvent) {
2173 if (this.hasClass(this.CLASS_NAME_PREFIX + "split-button-activeoption")) {
2177 this._bOptionPressed = false;
2182 this._showMenu(p_oEvent);
2184 this._bOptionPressed = true;
2192 * @method _onMenuShow
2193 * @description "show" event handler for the button's menu.
2195 * @param {String} p_sType String representing the name of the event
2198 _onMenuShow: function (p_sType) {
2200 Event.on(document, "mousedown", this._onDocumentMouseDown,
2203 var sState = (this.get("type") == "split") ? "activeoption" : "active";
2205 this.addStateCSSClasses(sState);
2211 * @method _onMenuHide
2212 * @description "hide" event handler for the button's menu.
2214 * @param {String} p_sType String representing the name of the event
2217 _onMenuHide: function (p_sType) {
2219 var sState = (this.get("type") == "split") ? "activeoption" : "active";
2221 this.removeStateCSSClasses(sState);
2224 if (this.get("type") == "split") {
2226 this._bOptionPressed = false;
2234 * @method _onMenuKeyDown
2235 * @description "keydown" event handler for the button's menu.
2237 * @param {String} p_sType String representing the name of the event
2239 * @param {Array} p_aArgs Array of arguments sent when the event
2242 _onMenuKeyDown: function (p_sType, p_aArgs) {
2244 var oEvent = p_aArgs[0];
2246 if (Event.getCharCode(oEvent) == 27) {
2250 if (this.get("type") == "split") {
2252 this._bOptionPressed = false;
2262 * @method _onMenuRender
2263 * @description "render" event handler for the button's menu.
2265 * @param {String} p_sType String representing the name of the
2266 * event thatwas fired.
2268 _onMenuRender: function (p_sType) {
2270 var oButtonElement = this.get("element"),
2271 oButtonParent = oButtonElement.parentNode,
2273 oMenuElement = oMenu.element,
2274 oSrcElement = oMenu.srcElement,
2278 if (oButtonParent != oMenuElement.parentNode) {
2280 oButtonParent.appendChild(oMenuElement);
2284 this._renderedMenu = true;
2286 // If the user has designated an <option> of the Menu's source
2287 // <select> element to be selected, sync the selectedIndex with
2288 // the "selectedMenuItem" Attribute.
2291 oSrcElement.nodeName.toLowerCase() === "select" &&
2292 oSrcElement.value) {
2295 oItem = oMenu.getItem(oSrcElement.selectedIndex);
2297 // Set the value of the "selectedMenuItem" attribute
2298 // silently since this is the initial set--synchronizing
2299 // the value of the source <SELECT> element in the DOM with
2300 // its corresponding Menu instance.
2302 this.set("selectedMenuItem", oItem, true);
2304 // Call the "_onSelectedMenuItemChange" method since the
2305 // attribute was set silently.
2307 this._onSelectedMenuItemChange({ newValue: oItem });
2316 * @method _onMenuClick
2317 * @description "click" event handler for the button's menu.
2319 * @param {String} p_sType String representing the name of the event
2321 * @param {Array} p_aArgs Array of arguments sent when the event
2324 _onMenuClick: function (p_sType, p_aArgs) {
2326 var oItem = p_aArgs[1],
2331 this.set("selectedMenuItem", oItem);
2333 oSrcElement = this.get("srcelement");
2335 if (oSrcElement && oSrcElement.type == "submit") {
2349 * @method _onSelectedMenuItemChange
2350 * @description "selectedMenuItemChange" event handler for the Button's
2351 * "selectedMenuItem" attribute.
2352 * @param {Event} event Object representing the DOM event object
2353 * passed back by the event utility (YAHOO.util.Event).
2355 _onSelectedMenuItemChange: function (event) {
2357 var oSelected = event.prevValue,
2358 oItem = event.newValue,
2359 sPrefix = this.CLASS_NAME_PREFIX;
2362 Dom.removeClass(oSelected.element, (sPrefix + "button-selectedmenuitem"));
2366 Dom.addClass(oItem.element, (sPrefix + "button-selectedmenuitem"));
2373 * @method _onLabelClick
2374 * @description "click" event handler for the Button's
2375 * <code><label></code> element.
2376 * @param {Event} event Object representing the DOM event object
2377 * passed back by the event utility (YAHOO.util.Event).
2379 _onLabelClick: function (event) {
2383 var sType = this.get("type");
2385 if (sType == "radio" || sType == "checkbox") {
2386 this.set("checked", (!this.get("checked")));
2396 * @method createButtonElement
2397 * @description Creates the button's HTML elements.
2398 * @param {String} p_sType String indicating the type of element
2400 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2401 * level-one-html.html#ID-58190037">HTMLElement</a>}
2403 createButtonElement: function (p_sType) {
2405 var sNodeName = this.NODE_NAME,
2406 oElement = document.createElement(sNodeName);
2408 oElement.innerHTML = "<" + sNodeName + " class=\"first-child\">" +
2409 (p_sType == "link" ? "<a></a>" :
2410 "<button type=\"button\"></button>") + "</" + sNodeName + ">";
2418 * @method addStateCSSClasses
2419 * @description Appends state-specific CSS classes to the button's root
2422 addStateCSSClasses: function (p_sState) {
2424 var sType = this.get("type"),
2425 sPrefix = this.CLASS_NAME_PREFIX;
2427 if (Lang.isString(p_sState)) {
2429 if (p_sState != "activeoption" && p_sState != "hoveroption") {
2431 this.addClass(sPrefix + this.CSS_CLASS_NAME + ("-" + p_sState));
2435 this.addClass(sPrefix + sType + ("-button-" + p_sState));
2443 * @method removeStateCSSClasses
2444 * @description Removes state-specific CSS classes to the button's root
2447 removeStateCSSClasses: function (p_sState) {
2449 var sType = this.get("type"),
2450 sPrefix = this.CLASS_NAME_PREFIX;
2452 if (Lang.isString(p_sState)) {
2454 this.removeClass(sPrefix + this.CSS_CLASS_NAME + ("-" + p_sState));
2455 this.removeClass(sPrefix + sType + ("-button-" + p_sState));
2463 * @method createHiddenFields
2464 * @description Creates the button's hidden form field and appends it
2465 * to its parent form.
2466 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2467 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
2469 createHiddenFields: function () {
2471 this.removeHiddenFields();
2473 var oForm = this.getForm(),
2485 bMenuSrcElementIsSelect = false;
2488 if (oForm && !this.get("disabled")) {
2490 sType = this.get("type");
2491 bCheckable = (sType == "checkbox" || sType == "radio");
2494 if ((bCheckable && this.get("checked")) || (m_oSubmitTrigger == this)) {
2497 oButtonField = createInputElement((bCheckable ? sType : "hidden"),
2498 this.get("name"), this.get("value"), this.get("checked"));
2505 oButtonField.style.display = "none";
2509 oForm.appendChild(oButtonField);
2519 if (Menu && oMenu && (oMenu instanceof Menu)) {
2522 oMenuItem = this.get("selectedMenuItem");
2523 oMenuSrcElement = oMenu.srcElement;
2524 bMenuSrcElementIsSelect = (oMenuSrcElement &&
2525 oMenuSrcElement.nodeName.toUpperCase() == "SELECT");
2529 oValue = (oMenuItem.value === null || oMenuItem.value === "") ?
2530 oMenuItem.cfg.getProperty("text") : oMenuItem.value;
2532 sButtonName = this.get("name");
2535 if (bMenuSrcElementIsSelect) {
2537 sMenuFieldName = oMenuSrcElement.name;
2540 else if (sButtonName) {
2542 sMenuFieldName = (sButtonName + "_options");
2547 if (oValue && sMenuFieldName) {
2549 oMenuField = createInputElement("hidden", sMenuFieldName, oValue);
2550 oForm.appendChild(oMenuField);
2555 else if (bMenuSrcElementIsSelect) {
2557 oMenuField = oForm.appendChild(oMenuSrcElement);
2564 if (oButtonField && oMenuField) {
2566 this._hiddenFields = [oButtonField, oMenuField];
2569 else if (!oButtonField && oMenuField) {
2571 this._hiddenFields = oMenuField;
2574 else if (oButtonField && !oMenuField) {
2576 this._hiddenFields = oButtonField;
2580 oReturnVal = this._hiddenFields;
2590 * @method removeHiddenFields
2591 * @description Removes the button's hidden form field(s) from its
2594 removeHiddenFields: function () {
2596 var oField = this._hiddenFields,
2600 function removeChild(p_oElement) {
2602 if (Dom.inDocument(p_oElement)) {
2604 p_oElement.parentNode.removeChild(p_oElement);
2613 if (Lang.isArray(oField)) {
2615 nFields = oField.length;
2623 removeChild(oField[i]);
2633 removeChild(oField);
2637 this._hiddenFields = null;
2645 * @method submitForm
2646 * @description Submits the form to which the button belongs. Returns
2647 * true if the form was submitted successfully, false if the submission
2652 submitForm: function () {
2654 var oForm = this.getForm(),
2656 oSrcElement = this.get("srcelement"),
2659 Boolean indicating if the event fired successfully
2660 (was not cancelled by any handlers)
2663 bSubmitForm = false,
2670 if (this.get("type") == "submit" || (oSrcElement && oSrcElement.type == "submit")) {
2672 m_oSubmitTrigger = this;
2677 if (UA.ie && (UA.ie < 9)) {
2679 bSubmitForm = oForm.fireEvent("onsubmit");
2682 else { // Gecko, Opera, and Safari
2684 oEvent = document.createEvent("HTMLEvents");
2685 oEvent.initEvent("submit", true, true);
2687 bSubmitForm = oForm.dispatchEvent(oEvent);
2693 In IE and Safari, dispatching a "submit" event to a form
2694 WILL cause the form's "submit" event to fire, but WILL NOT
2695 submit the form. Therefore, we need to call the "submit"
2699 if ((UA.ie || UA.webkit) && bSubmitForm) {
2714 * @description The Button class's initialization method.
2715 * @param {String} p_oElement String specifying the id attribute of the
2716 * <code><input></code>, <code><button></code>,
2717 * <code><a></code>, or <code><span></code> element to
2718 * be used to create the button.
2719 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2720 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://
2721 * www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
2722 * #ID-34812697">HTMLButtonElement</a>|<a href="http://www.w3.org/TR
2723 * /2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-33759296">
2724 * HTMLElement</a>} p_oElement Object reference for the
2725 * <code><input></code>, <code><button></code>,
2726 * <code><a></code>, or <code><span></code> element to be
2727 * used to create the button.
2728 * @param {Object} p_oElement Object literal specifying a set of
2729 * configuration attributes used to create the button.
2730 * @param {Object} p_oAttributes Optional. Object literal specifying a
2731 * set of configuration attributes used to create the button.
2733 init: function (p_oElement, p_oAttributes) {
2735 var sNodeName = p_oAttributes.type == "link" ? "a" : "button",
2736 oSrcElement = p_oAttributes.srcelement,
2737 oButton = p_oElement.getElementsByTagName(sNodeName)[0],
2743 oInput = p_oElement.getElementsByTagName("input")[0];
2748 oButton = document.createElement("button");
2749 oButton.setAttribute("type", "button");
2751 oInput.parentNode.replaceChild(oButton, oInput);
2757 this._button = oButton;
2760 YAHOO.widget.Button.superclass.init.call(this, p_oElement, p_oAttributes);
2763 var sId = this.get("id"),
2764 sButtonId = sId + "-button";
2767 oButton.id = sButtonId;
2774 var hasLabel = function (element) {
2776 return (element.htmlFor === sId);
2781 var setLabel = function () {
2783 oLabel.setAttribute((UA.ie ? "htmlFor" : "for"), sButtonId);
2788 if (oSrcElement && this.get("type") != "link") {
2790 aLabels = Dom.getElementsBy(hasLabel, "label");
2792 if (Lang.isArray(aLabels) && aLabels.length > 0) {
2794 oLabel = aLabels[0];
2801 m_oButtons[sId] = this;
2803 var sPrefix = this.CLASS_NAME_PREFIX;
2805 this.addClass(sPrefix + this.CSS_CLASS_NAME);
2806 this.addClass(sPrefix + this.get("type") + "-button");
2808 Event.on(this._button, "focus", this._onFocus, null, this);
2809 this.on("mouseover", this._onMouseOver);
2810 this.on("mousedown", this._onMouseDown);
2811 this.on("mouseup", this._onMouseUp);
2812 this.on("click", this._onClick);
2814 // Need to reset the value of the "onclick" Attribute so that any
2815 // handlers registered via the "onclick" Attribute are fired after
2816 // Button's default "_onClick" listener.
2818 var fnOnClick = this.get("onclick");
2820 this.set("onclick", null);
2821 this.set("onclick", fnOnClick);
2823 this.on("dblclick", this._onDblClick);
2830 if (this.get("replaceLabel")) {
2832 this.set("label", oLabel.innerHTML);
2834 oParentNode = oLabel.parentNode;
2836 oParentNode.removeChild(oLabel);
2841 this.on("appendTo", setLabel);
2843 Event.on(oLabel, "click", this._onLabelClick, null, this);
2845 this._label = oLabel;
2851 this.on("appendTo", this._onAppendTo);
2855 var oContainer = this.get("container"),
2856 oElement = this.get("element"),
2857 bElInDoc = Dom.inDocument(oElement);
2862 if (oSrcElement && oSrcElement != oElement) {
2864 oParentNode = oSrcElement.parentNode;
2868 oParentNode.removeChild(oSrcElement);
2874 if (Lang.isString(oContainer)) {
2876 Event.onContentReady(oContainer, this.appendTo, oContainer, this);
2881 this.on("init", function () {
2883 Lang.later(0, this, this.appendTo, oContainer);
2890 else if (!bElInDoc && oSrcElement && oSrcElement != oElement) {
2892 oParentNode = oSrcElement.parentNode;
2896 this.fireEvent("beforeAppendTo", {
2897 type: "beforeAppendTo",
2901 oParentNode.replaceChild(oElement, oSrcElement);
2903 this.fireEvent("appendTo", {
2911 else if (this.get("type") != "link" && bElInDoc && oSrcElement &&
2912 oSrcElement == oElement) {
2914 this._addListenersToForm();
2920 this.fireEvent("init", {
2929 * @method initAttributes
2930 * @description Initializes all of the configuration attributes used to
2931 * create the button.
2932 * @param {Object} p_oAttributes Object literal specifying a set of
2933 * configuration attributes used to create the button.
2935 initAttributes: function (p_oAttributes) {
2937 var oAttributes = p_oAttributes || {};
2939 YAHOO.widget.Button.superclass.initAttributes.call(this,
2945 * @description String specifying the button's type. Possible
2946 * values are: "push," "link," "submit," "reset," "checkbox,"
2947 * "radio," "menu," and "split."
2952 this.setAttributeConfig("type", {
2954 value: (oAttributes.type || "push"),
2955 validator: Lang.isString,
2957 method: this._setType
2964 * @description {HTML} specifying the button's text label
2969 this.setAttributeConfig("label", {
2971 value: oAttributes.label,
2972 validator: Lang.isString,
2973 method: this._setLabel
2980 * @description Object specifying the value for the button.
2984 this.setAttributeConfig("value", {
2986 value: oAttributes.value
2993 * @description String specifying the name for the button.
2997 this.setAttributeConfig("name", {
2999 value: oAttributes.name,
3000 validator: Lang.isString
3006 * @attribute tabindex
3007 * @description Number specifying the tabindex for the button.
3011 this.setAttributeConfig("tabindex", {
3013 value: oAttributes.tabindex,
3014 validator: Lang.isNumber,
3015 method: this._setTabIndex
3022 * @description String specifying the title for the button.
3026 this.configureAttribute("title", {
3028 value: oAttributes.title,
3029 validator: Lang.isString,
3030 method: this._setTitle
3036 * @attribute disabled
3037 * @description Boolean indicating if the button should be disabled.
3038 * (Disabled buttons are dimmed and will not respond to user input
3039 * or fire events. Does not apply to button's of type "link.")
3043 this.setAttributeConfig("disabled", {
3045 value: (oAttributes.disabled || false),
3046 validator: Lang.isBoolean,
3047 method: this._setDisabled
3054 * @description String specifying the href for the button. Applies
3055 * only to buttons of type "link."
3058 this.setAttributeConfig("href", {
3060 value: oAttributes.href,
3061 validator: Lang.isString,
3062 method: this._setHref
3069 * @description String specifying the target for the button.
3070 * Applies only to buttons of type "link."
3073 this.setAttributeConfig("target", {
3075 value: oAttributes.target,
3076 validator: Lang.isString,
3077 method: this._setTarget
3083 * @attribute checked
3084 * @description Boolean indicating if the button is checked.
3085 * Applies only to buttons of type "radio" and "checkbox."
3089 this.setAttributeConfig("checked", {
3091 value: (oAttributes.checked || false),
3092 validator: Lang.isBoolean,
3093 method: this._setChecked
3099 * @attribute container
3100 * @description HTML element reference or string specifying the id
3101 * attribute of the HTML element that the button's markup should be
3103 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3104 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3108 this.setAttributeConfig("container", {
3110 value: oAttributes.container,
3117 * @attribute srcelement
3118 * @description Object reference to the HTML element (either
3119 * <code><input></code> or <code><span></code>)
3120 * used to create the button.
3121 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3122 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3126 this.setAttributeConfig("srcelement", {
3128 value: oAttributes.srcelement,
3136 * @description Object specifying the menu for the button.
3137 * The value can be one of the following:
3139 * <li>Object specifying a rendered <a href="YAHOO.widget.Menu.html">
3140 * YAHOO.widget.Menu</a> instance.</li>
3141 * <li>Object specifying a rendered <a href="YAHOO.widget.Overlay.html">
3142 * YAHOO.widget.Overlay</a> instance.</li>
3143 * <li>String specifying the id attribute of the <code><div>
3144 * </code> element used to create the menu. By default the menu
3145 * will be created as an instance of
3146 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>.
3147 * If the <a href="YAHOO.widget.Menu.html#CSS_CLASS_NAME">
3148 * default CSS class name for YAHOO.widget.Menu</a> is applied to
3149 * the <code><div></code> element, it will be created as an
3150 * instance of <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu
3151 * </a>.</li><li>String specifying the id attribute of the
3152 * <code><select></code> element used to create the menu.
3153 * </li><li>Object specifying the <code><div></code> element
3154 * used to create the menu.</li>
3155 * <li>Object specifying the <code><select></code> element
3156 * used to create the menu.</li>
3157 * <li>Array of object literals, each representing a set of
3158 * <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>
3159 * configuration attributes.</li>
3160 * <li>Array of strings representing the text labels for each menu
3161 * item in the menu.</li>
3163 * @type <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>|<a
3164 * href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|<a
3165 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3166 * one-html.html#ID-58190037">HTMLElement</a>|String|Array
3170 this.setAttributeConfig("menu", {
3173 method: this._setMenu,
3180 * @attribute lazyloadmenu
3181 * @description Boolean indicating the value to set for the
3182 * <a href="YAHOO.widget.Menu.html#lazyLoad">"lazyload"</a>
3183 * configuration property of the button's menu. Setting
3184 * "lazyloadmenu" to <code>true </code> will defer rendering of
3185 * the button's menu until the first time it is made visible.
3186 * If "lazyloadmenu" is set to <code>false</code>, the button's
3187 * menu will be rendered immediately if the button is in the
3188 * document, or in response to the button's "appendTo" event if
3189 * the button is not yet in the document. In either case, the
3190 * menu is rendered into the button's parent HTML element.
3191 * <em>This attribute does not apply if a
3192 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a> or
3193 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
3194 * instance is passed as the value of the button's "menu"
3195 * configuration attribute. <a href="YAHOO.widget.Menu.html">
3196 * YAHOO.widget.Menu</a> or <a href="YAHOO.widget.Overlay.html">
3197 * YAHOO.widget.Overlay</a> instances should be rendered before
3198 * being set as the value for the "menu" configuration
3204 this.setAttributeConfig("lazyloadmenu", {
3206 value: (oAttributes.lazyloadmenu === false ? false : true),
3207 validator: Lang.isBoolean,
3214 * @attribute menuclassname
3215 * @description String representing the CSS class name to be
3216 * applied to the root element of the button's menu.
3218 * @default "yui-button-menu"
3221 this.setAttributeConfig("menuclassname", {
3223 value: (oAttributes.menuclassname || (this.CLASS_NAME_PREFIX + "button-menu")),
3224 validator: Lang.isString,
3225 method: this._setMenuClassName,
3232 * @attribute menuminscrollheight
3233 * @description Number defining the minimum threshold for the "menumaxheight"
3234 * configuration attribute. When set this attribute is automatically applied
3239 this.setAttributeConfig("menuminscrollheight", {
3241 value: (oAttributes.menuminscrollheight || 90),
3242 validator: Lang.isNumber
3248 * @attribute menumaxheight
3249 * @description Number defining the maximum height (in pixels) for a menu's
3250 * body element (<code><div class="bd"<</code>). Once a menu's body
3251 * exceeds this height, the contents of the body are scrolled to maintain
3252 * this value. This value cannot be set lower than the value of the
3253 * "minscrollheight" configuration property.
3257 this.setAttributeConfig("menumaxheight", {
3259 value: (oAttributes.menumaxheight || 0),
3260 validator: Lang.isNumber
3266 * @attribute menualignment
3267 * @description Array defining how the Button's Menu is aligned to the Button.
3268 * The default value of ["tl", "bl"] aligns the Menu's top left corner to the Button's
3269 * bottom left corner.
3271 * @default ["tl", "bl"]
3273 this.setAttributeConfig("menualignment", {
3275 value: (oAttributes.menualignment || ["tl", "bl"]),
3276 validator: Lang.isArray
3282 * @attribute selectedMenuItem
3283 * @description Object representing the item in the button's menu
3284 * that is currently selected.
3285 * @type YAHOO.widget.MenuItem
3288 this.setAttributeConfig("selectedMenuItem", {
3296 * @attribute onclick
3297 * @description Object literal representing the code to be executed
3298 * when the button is clicked. Format:<br> <code> {<br>
3299 * <strong>fn:</strong> Function, // The handler to call
3300 * when the event fires.<br> <strong>obj:</strong> Object,
3301 * // An object to pass back to the handler.<br>
3302 * <strong>scope:</strong> Object // The object to use
3303 * for the scope of the handler.<br> } </code>
3307 this.setAttributeConfig("onclick", {
3309 value: oAttributes.onclick,
3310 method: this._setOnClick
3316 * @attribute focusmenu
3317 * @description Boolean indicating whether or not the button's menu
3318 * should be focused when it is made visible.
3322 this.setAttributeConfig("focusmenu", {
3324 value: (oAttributes.focusmenu === false ? false : true),
3325 validator: Lang.isBoolean
3331 * @attribute replaceLabel
3332 * @description Boolean indicating whether or not the text of the
3333 * button's <code><label></code> element should be used as
3334 * the source for the button's label configuration attribute and
3335 * removed from the DOM.
3339 this.setAttributeConfig("replaceLabel", {
3342 validator: Lang.isBoolean,
3352 * @description Causes the button to receive the focus and fires the
3353 * button's "focus" event.
3355 focus: function () {
3357 if (!this.get("disabled")) {
3358 //Adding a try/catch in case the element is not
3359 // visible by the time it's focus is being called.
3360 // for example, on a dialog that closes on button click
3362 this._button.focus();
3372 * @description Causes the button to lose focus and fires the button's
3377 if (!this.get("disabled")) {
3378 //Adding a try/catch in case the element is not
3379 // visible by the time it's focus is being called.
3380 // for example, on a dialog that closes on button click
3382 this._button.blur();
3392 * @description Returns a boolean indicating whether or not the button
3396 hasFocus: function () {
3398 return (m_oFocusedButton == this);
3405 * @description Returns a boolean indicating whether or not the button
3409 isActive: function () {
3411 return this.hasClass(this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME + "-active");
3418 * @description Returns a reference to the button's menu.
3419 * @return {<a href="YAHOO.widget.Overlay.html">
3420 * YAHOO.widget.Overlay</a>|<a
3421 * href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
3423 getMenu: function () {
3432 * @description Returns a reference to the button's parent form.
3433 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-
3434 * 20000929/level-one-html.html#ID-40002357">HTMLFormElement</a>}
3436 getForm: function () {
3438 var oButton = this._button,
3443 oForm = oButton.form;
3453 * @method getHiddenFields
3454 * @description Returns an <code><input></code> element or
3455 * array of form elements used to represent the button when its parent
3456 * form is submitted.
3457 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3458 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
3460 getHiddenFields: function () {
3462 return this._hiddenFields;
3469 * @description Removes the button's element from its parent element and
3470 * removes all event handlers.
3472 destroy: function () {
3475 var oElement = this.get("element"),
3477 oLabel = this._label,
3484 if (m_oOverlayManager && m_oOverlayManager.find(oMenu)) {
3486 m_oOverlayManager.remove(oMenu);
3495 Event.purgeElement(oElement);
3496 Event.purgeElement(this._button);
3497 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
3498 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
3499 Event.removeListener(document, "mousedown", this._onDocumentMouseDown);
3504 Event.removeListener(oLabel, "click", this._onLabelClick);
3506 oParentNode = oLabel.parentNode;
3507 oParentNode.removeChild(oLabel);
3512 var oForm = this.getForm();
3516 Event.removeListener(oForm, "reset", this._onFormReset);
3517 Event.removeListener(oForm, "submit", this._onFormSubmit);
3522 this.unsubscribeAll();
3524 oParentNode = oElement.parentNode;
3528 oParentNode.removeChild(oElement);
3533 delete m_oButtons[this.get("id")];
3535 var sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME);
3537 aButtons = Dom.getElementsByClassName(sClass,
3538 this.NODE_NAME, oForm);
3540 if (Lang.isArray(aButtons) && aButtons.length === 0) {
3542 Event.removeListener(oForm, "keypress",
3543 YAHOO.widget.Button.onFormKeyPress);
3551 fireEvent: function (p_sType , p_aArgs) {
3553 var sType = arguments[0];
3555 // Disabled buttons should not respond to DOM events
3557 if (this.DOM_EVENTS[sType] && this.get("disabled")) {
3563 return YAHOO.widget.Button.superclass.fireEvent.apply(this, arguments);
3570 * @description Returns a string representing the button.
3573 toString: function () {
3575 return ("Button " + this.get("id"));
3583 * @method YAHOO.widget.Button.onFormKeyPress
3584 * @description "keypress" event handler for the button's form.
3585 * @param {Event} p_oEvent Object representing the DOM event object passed
3586 * back by the event utility (YAHOO.util.Event).
3588 YAHOO.widget.Button.onFormKeyPress = function (p_oEvent) {
3590 var oTarget = Event.getTarget(p_oEvent),
3591 nCharCode = Event.getCharCode(p_oEvent),
3592 sNodeName = oTarget.nodeName && oTarget.nodeName.toUpperCase(),
3593 sType = oTarget.type,
3596 Boolean indicating if the form contains any enabled or
3597 disabled YUI submit buttons
3600 bFormContainsYUIButtons = false,
3604 oYUISubmitButton, // The form's first, enabled YUI submit button
3607 The form's first, enabled HTML submit button that precedes any
3611 oPrecedingSubmitButton,
3616 function isSubmitButton(p_oElement) {
3621 switch (p_oElement.nodeName.toUpperCase()) {
3626 if (p_oElement.type == "submit" && !p_oElement.disabled) {
3628 if (!bFormContainsYUIButtons && !oPrecedingSubmitButton) {
3630 oPrecedingSubmitButton = p_oElement;
3641 sId = p_oElement.id;
3645 oButton = m_oButtons[sId];
3649 bFormContainsYUIButtons = true;
3651 if (!oButton.get("disabled")) {
3653 oSrcElement = oButton.get("srcelement");
3655 if (!oYUISubmitButton && (oButton.get("type") == "submit" ||
3656 (oSrcElement && oSrcElement.type == "submit"))) {
3658 oYUISubmitButton = oButton;
3675 if (nCharCode == 13 && ((sNodeName == "INPUT" && (sType == "text" ||
3676 sType == "password" || sType == "checkbox" || sType == "radio" ||
3677 sType == "file")) || sNodeName == "SELECT")) {
3679 Dom.getElementsBy(isSubmitButton, "*", this);
3682 if (oPrecedingSubmitButton) {
3685 Need to set focus to the first enabled submit button
3686 to make sure that IE includes its name and value
3687 in the form's data set.
3690 oPrecedingSubmitButton.focus();
3693 else if (!oPrecedingSubmitButton && oYUISubmitButton) {
3696 Need to call "preventDefault" to ensure that the form doesn't end up getting
3700 Event.preventDefault(p_oEvent);
3705 oYUISubmitButton.get("element").fireEvent("onclick");
3710 oEvent = document.createEvent("HTMLEvents");
3711 oEvent.initEvent("click", true, true);
3714 if (UA.gecko < 1.9) {
3716 oYUISubmitButton.fireEvent("click", oEvent);
3721 oYUISubmitButton.get("element").dispatchEvent(oEvent);
3735 * @method YAHOO.widget.Button.addHiddenFieldsToForm
3736 * @description Searches the specified form and adds hidden fields for
3737 * instances of YAHOO.widget.Button that are of type "radio," "checkbox,"
3738 * "menu," and "split."
3739 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3740 * one-html.html#ID-40002357">HTMLFormElement</a>} p_oForm Object reference
3741 * for the form to search.
3743 YAHOO.widget.Button.addHiddenFieldsToForm = function (p_oForm) {
3745 var proto = YAHOO.widget.Button.prototype,
3746 aButtons = Dom.getElementsByClassName(
3747 (proto.CLASS_NAME_PREFIX + proto.CSS_CLASS_NAME),
3751 nButtons = aButtons.length,
3759 for (i = 0; i < nButtons; i++) {
3761 sId = aButtons[i].id;
3765 oButton = m_oButtons[sId];
3769 oButton.createHiddenFields();
3783 * @method YAHOO.widget.Button.getButton
3784 * @description Returns a button with the specified id.
3785 * @param {String} p_sId String specifying the id of the root node of the
3786 * HTML element representing the button to be retrieved.
3787 * @return {YAHOO.widget.Button}
3789 YAHOO.widget.Button.getButton = function (p_sId) {
3791 return m_oButtons[p_sId];
3801 * @description Fires when the menu item receives focus. Passes back a
3802 * single object representing the original DOM event object passed back by
3803 * the event utility (YAHOO.util.Event) when the event was fired. See
3804 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3805 * for more information on listening for this event.
3806 * @type YAHOO.util.CustomEvent
3812 * @description Fires when the menu item loses the input focus. Passes back
3813 * a single object representing the original DOM event object passed back by
3814 * the event utility (YAHOO.util.Event) when the event was fired. See
3815 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for
3816 * more information on listening for this event.
3817 * @type YAHOO.util.CustomEvent
3823 * @description Fires when the user invokes the button's option. Passes
3824 * back a single object representing the original DOM event (either
3825 * "mousedown" or "keydown") that caused the "option" event to fire. See
3826 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3827 * for more information on listening for this event.
3828 * @type YAHOO.util.CustomEvent
3834 // Shorthard for utilities
3836 var Dom = YAHOO.util.Dom,
3837 Event = YAHOO.util.Event,
3839 Button = YAHOO.widget.Button,
3841 // Private collection of radio buttons
3848 * The ButtonGroup class creates a set of buttons that are mutually
3849 * exclusive; checking one button in the set will uncheck all others in the
3851 * @param {String} p_oElement String specifying the id attribute of the
3852 * <code><div></code> element of the button group.
3853 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3854 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
3855 * specifying the <code><div></code> element of the button group.
3856 * @param {Object} p_oElement Object literal specifying a set of
3857 * configuration attributes used to create the button group.
3858 * @param {Object} p_oAttributes Optional. Object literal specifying a set
3859 * of configuration attributes used to create the button group.
3860 * @namespace YAHOO.widget
3861 * @class ButtonGroup
3863 * @extends YAHOO.util.Element
3865 YAHOO.widget.ButtonGroup = function (p_oElement, p_oAttributes) {
3867 var fnSuperClass = YAHOO.widget.ButtonGroup.superclass.constructor,
3872 if (arguments.length == 1 && !Lang.isString(p_oElement) &&
3873 !p_oElement.nodeName) {
3875 if (!p_oElement.id) {
3877 sId = Dom.generateId();
3879 p_oElement.id = sId;
3886 fnSuperClass.call(this, (this._createGroupElement()), p_oElement);
3889 else if (Lang.isString(p_oElement)) {
3891 oElement = Dom.get(p_oElement);
3895 if (oElement.nodeName.toUpperCase() == this.NODE_NAME) {
3898 fnSuperClass.call(this, oElement, p_oAttributes);
3907 sNodeName = p_oElement.nodeName.toUpperCase();
3909 if (sNodeName && sNodeName == this.NODE_NAME) {
3911 if (!p_oElement.id) {
3913 p_oElement.id = Dom.generateId();
3919 fnSuperClass.call(this, p_oElement, p_oAttributes);
3928 YAHOO.extend(YAHOO.widget.ButtonGroup, YAHOO.util.Element, {
3931 // Protected properties
3935 * @property _buttons
3936 * @description Array of buttons in the button group.
3949 * @property NODE_NAME
3950 * @description The name of the tag to be used for the button
3960 * @property CLASS_NAME_PREFIX
3961 * @description Prefix used for all class names applied to a ButtonGroup.
3966 CLASS_NAME_PREFIX: "yui-",
3970 * @property CSS_CLASS_NAME
3971 * @description String representing the CSS class(es) to be applied
3972 * to the button group's element.
3973 * @default "buttongroup"
3977 CSS_CLASS_NAME: "buttongroup",
3981 // Protected methods
3985 * @method _createGroupElement
3986 * @description Creates the button group's element.
3988 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3989 * level-one-html.html#ID-22445964">HTMLDivElement</a>}
3991 _createGroupElement: function () {
3993 var oElement = document.createElement(this.NODE_NAME);
4001 // Protected attribute setter methods
4005 * @method _setDisabled
4006 * @description Sets the value of the button groups's
4007 * "disabled" attribute.
4009 * @param {Boolean} p_bDisabled Boolean indicating the value for
4010 * the button group's "disabled" attribute.
4012 _setDisabled: function (p_bDisabled) {
4014 var nButtons = this.getCount(),
4023 this._buttons[i].set("disabled", p_bDisabled);
4034 // Protected event handlers
4038 * @method _onKeyDown
4039 * @description "keydown" event handler for the button group.
4041 * @param {Event} p_oEvent Object representing the DOM event object
4042 * passed back by the event utility (YAHOO.util.Event).
4044 _onKeyDown: function (p_oEvent) {
4046 var oTarget = Event.getTarget(p_oEvent),
4047 nCharCode = Event.getCharCode(p_oEvent),
4048 sId = oTarget.parentNode.parentNode.id,
4049 oButton = m_oButtons[sId],
4053 if (nCharCode == 37 || nCharCode == 38) {
4055 nIndex = (oButton.index === 0) ?
4056 (this._buttons.length - 1) : (oButton.index - 1);
4059 else if (nCharCode == 39 || nCharCode == 40) {
4061 nIndex = (oButton.index === (this._buttons.length - 1)) ?
4062 0 : (oButton.index + 1);
4070 this.getButton(nIndex).focus();
4078 * @method _onAppendTo
4079 * @description "appendTo" event handler for the button group.
4081 * @param {Event} p_oEvent Object representing the event that was fired.
4083 _onAppendTo: function (p_oEvent) {
4085 var aButtons = this._buttons,
4086 nButtons = aButtons.length,
4089 for (i = 0; i < nButtons; i++) {
4091 aButtons[i].appendTo(this.get("element"));
4099 * @method _onButtonCheckedChange
4100 * @description "checkedChange" event handler for each button in the
4103 * @param {Event} p_oEvent Object representing the event that was fired.
4104 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4105 * p_oButton Object representing the button that fired the event.
4107 _onButtonCheckedChange: function (p_oEvent, p_oButton) {
4109 var bChecked = p_oEvent.newValue,
4110 oCheckedButton = this.get("checkedButton");
4112 if (bChecked && oCheckedButton != p_oButton) {
4114 if (oCheckedButton) {
4116 oCheckedButton.set("checked", false, true);
4120 this.set("checkedButton", p_oButton);
4121 this.set("value", p_oButton.get("value"));
4124 else if (oCheckedButton && !oCheckedButton.set("checked")) {
4126 oCheckedButton.set("checked", true, true);
4139 * @description The ButtonGroup class's initialization method.
4140 * @param {String} p_oElement String specifying the id attribute of the
4141 * <code><div></code> element of the button group.
4142 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4143 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
4144 * specifying the <code><div></code> element of the button group.
4145 * @param {Object} p_oElement Object literal specifying a set of
4146 * configuration attributes used to create the button group.
4147 * @param {Object} p_oAttributes Optional. Object literal specifying a
4148 * set of configuration attributes used to create the button group.
4150 init: function (p_oElement, p_oAttributes) {
4154 YAHOO.widget.ButtonGroup.superclass.init.call(this, p_oElement,
4157 this.addClass(this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME);
4160 var sClass = (YAHOO.widget.Button.prototype.CLASS_NAME_PREFIX + "radio-button"),
4161 aButtons = this.getElementsByClassName(sClass);
4165 if (aButtons.length > 0) {
4168 this.addButtons(aButtons);
4174 function isRadioButton(p_oElement) {
4176 return (p_oElement.type == "radio");
4181 Dom.getElementsBy(isRadioButton, "input", this.get("element"));
4184 if (aButtons.length > 0) {
4187 this.addButtons(aButtons);
4191 this.on("keydown", this._onKeyDown);
4192 this.on("appendTo", this._onAppendTo);
4195 var oContainer = this.get("container");
4199 if (Lang.isString(oContainer)) {
4201 Event.onContentReady(oContainer, function () {
4203 this.appendTo(oContainer);
4210 this.appendTo(oContainer);
4222 * @method initAttributes
4223 * @description Initializes all of the configuration attributes used to
4224 * create the button group.
4225 * @param {Object} p_oAttributes Object literal specifying a set of
4226 * configuration attributes used to create the button group.
4228 initAttributes: function (p_oAttributes) {
4230 var oAttributes = p_oAttributes || {};
4232 YAHOO.widget.ButtonGroup.superclass.initAttributes.call(
4238 * @description String specifying the name for the button group.
4239 * This name will be applied to each button in the button group.
4243 this.setAttributeConfig("name", {
4245 value: oAttributes.name,
4246 validator: Lang.isString
4252 * @attribute disabled
4253 * @description Boolean indicating if the button group should be
4254 * disabled. Disabling the button group will disable each button
4255 * in the button group. Disabled buttons are dimmed and will not
4256 * respond to user input or fire events.
4260 this.setAttributeConfig("disabled", {
4262 value: (oAttributes.disabled || false),
4263 validator: Lang.isBoolean,
4264 method: this._setDisabled
4271 * @description Object specifying the value for the button group.
4275 this.setAttributeConfig("value", {
4277 value: oAttributes.value
4283 * @attribute container
4284 * @description HTML element reference or string specifying the id
4285 * attribute of the HTML element that the button group's markup
4286 * should be rendered into.
4287 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4288 * level-one-html.html#ID-58190037">HTMLElement</a>|String
4292 this.setAttributeConfig("container", {
4294 value: oAttributes.container,
4301 * @attribute checkedButton
4302 * @description Reference for the button in the button group that
4304 * @type {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4307 this.setAttributeConfig("checkedButton", {
4318 * @description Adds the button to the button group.
4319 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4320 * p_oButton Object reference for the <a href="YAHOO.widget.Button.html">
4321 * YAHOO.widget.Button</a> instance to be added to the button group.
4322 * @param {String} p_oButton String specifying the id attribute of the
4323 * <code><input></code> or <code><span></code> element
4324 * to be used to create the button to be added to the button group.
4325 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4326 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="
4327 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
4328 * ID-33759296">HTMLElement</a>} p_oButton Object reference for the
4329 * <code><input></code> or <code><span></code> element
4330 * to be used to create the button to be added to the button group.
4331 * @param {Object} p_oButton Object literal specifying a set of
4332 * <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4333 * configuration attributes used to configure the button to be added to
4335 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4337 addButton: function (p_oButton) {
4347 if (p_oButton instanceof Button &&
4348 p_oButton.get("type") == "radio") {
4350 oButton = p_oButton;
4353 else if (!Lang.isString(p_oButton) && !p_oButton.nodeName) {
4355 p_oButton.type = "radio";
4357 oButton = new Button(p_oButton);
4362 oButton = new Button(p_oButton, { type: "radio" });
4369 nIndex = this._buttons.length;
4370 sButtonName = oButton.get("name");
4371 sGroupName = this.get("name");
4373 oButton.index = nIndex;
4375 this._buttons[nIndex] = oButton;
4376 m_oButtons[oButton.get("id")] = oButton;
4379 if (sButtonName != sGroupName) {
4381 oButton.set("name", sGroupName);
4386 if (this.get("disabled")) {
4388 oButton.set("disabled", true);
4393 if (oButton.get("checked")) {
4395 this.set("checkedButton", oButton);
4400 oButtonElement = oButton.get("element");
4401 oGroupElement = this.get("element");
4403 if (oButtonElement.parentNode != oGroupElement) {
4405 oGroupElement.appendChild(oButtonElement);
4410 oButton.on("checkedChange",
4411 this._onButtonCheckedChange, oButton, this);
4422 * @method addButtons
4423 * @description Adds the array of buttons to the button group.
4424 * @param {Array} p_aButtons Array of <a href="YAHOO.widget.Button.html">
4425 * YAHOO.widget.Button</a> instances to be added
4426 * to the button group.
4427 * @param {Array} p_aButtons Array of strings specifying the id
4428 * attribute of the <code><input></code> or <code><span>
4429 * </code> elements to be used to create the buttons to be added to the
4431 * @param {Array} p_aButtons Array of object references for the
4432 * <code><input></code> or <code><span></code> elements
4433 * to be used to create the buttons to be added to the button group.
4434 * @param {Array} p_aButtons Array of object literals, each containing
4435 * a set of <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4436 * configuration attributes used to configure each button to be added
4437 * to the button group.
4440 addButtons: function (p_aButtons) {
4447 if (Lang.isArray(p_aButtons)) {
4449 nButtons = p_aButtons.length;
4454 for (i = 0; i < nButtons; i++) {
4456 oButton = this.addButton(p_aButtons[i]);
4460 aButtons[aButtons.length] = oButton;
4476 * @method removeButton
4477 * @description Removes the button at the specified index from the
4479 * @param {Number} p_nIndex Number specifying the index of the button
4480 * to be removed from the button group.
4482 removeButton: function (p_nIndex) {
4484 var oButton = this.getButton(p_nIndex),
4491 this._buttons.splice(p_nIndex, 1);
4492 delete m_oButtons[oButton.get("id")];
4494 oButton.removeListener("checkedChange",
4495 this._onButtonCheckedChange);
4500 nButtons = this._buttons.length;
4504 i = this._buttons.length - 1;
4508 this._buttons[i].index = i;
4523 * @description Returns the button at the specified index.
4524 * @param {Number} p_nIndex The index of the button to retrieve from the
4526 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4528 getButton: function (p_nIndex) {
4530 return this._buttons[p_nIndex];
4536 * @method getButtons
4537 * @description Returns an array of the buttons in the button group.
4540 getButtons: function () {
4542 return this._buttons;
4549 * @description Returns the number of buttons in the button group.
4552 getCount: function () {
4554 return this._buttons.length;
4561 * @description Sets focus to the button at the specified index.
4562 * @param {Number} p_nIndex Number indicating the index of the button
4565 focus: function (p_nIndex) {
4571 if (Lang.isNumber(p_nIndex)) {
4573 oButton = this._buttons[p_nIndex];
4584 nButtons = this.getCount();
4586 for (i = 0; i < nButtons; i++) {
4588 oButton = this._buttons[i];
4590 if (!oButton.get("disabled")) {
4606 * @description Checks the button at the specified index.
4607 * @param {Number} p_nIndex Number indicating the index of the button
4610 check: function (p_nIndex) {
4612 var oButton = this.getButton(p_nIndex);
4616 oButton.set("checked", true);
4625 * @description Removes the button group's element from its parent
4626 * element and removes all event handlers.
4628 destroy: function () {
4631 var nButtons = this._buttons.length,
4632 oElement = this.get("element"),
4633 oParentNode = oElement.parentNode,
4638 i = this._buttons.length - 1;
4642 this._buttons[i].destroy();
4650 Event.purgeElement(oElement);
4653 oParentNode.removeChild(oElement);
4660 * @description Returns a string representing the button group.
4663 toString: function () {
4665 return ("ButtonGroup " + this.get("id"));
4672 YAHOO.register("button", YAHOO.widget.Button, {version: "2.9.0", build: "2800"});