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(),
188 sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME),
196 * @method setAttributeFromDOMAttribute
197 * @description Gets the value of the specified DOM attribute and sets it
198 * into the collection of configuration attributes used to configure
201 * @param {String} p_sAttribute String representing the name of the
202 * attribute to retrieve from the DOM element.
204 function setAttributeFromDOMAttribute(p_sAttribute) {
206 if (!(p_sAttribute in p_oAttributes)) {
209 Need to use "getAttributeNode" instead of "getAttribute"
210 because using "getAttribute," IE will return the innerText
211 of a <code><button></code> for the value attribute
212 rather than the value of the "value" attribute.
215 oAttribute = p_oElement.getAttributeNode(p_sAttribute);
218 if (oAttribute && ("value" in oAttribute)) {
220 YAHOO.log("Setting attribute \"" + p_sAttribute +
221 "\" using source element's attribute value of \"" +
222 oAttribute.value + "\"", "info", me.toString());
224 p_oAttributes[p_sAttribute] = oAttribute.value;
234 * @method setFormElementProperties
235 * @description Gets the value of the attributes from the form element
236 * and sets them into the collection of configuration attributes used to
237 * configure the button.
240 function setFormElementProperties() {
242 setAttributeFromDOMAttribute("type");
244 if (p_oAttributes.type == "button") {
246 p_oAttributes.type = "push";
250 if (!("disabled" in p_oAttributes)) {
252 p_oAttributes.disabled = p_oElement.disabled;
256 setAttributeFromDOMAttribute("name");
257 setAttributeFromDOMAttribute("value");
258 setAttributeFromDOMAttribute("title");
263 switch (sSrcElementNodeName) {
267 p_oAttributes.type = "link";
269 setAttributeFromDOMAttribute("href");
270 setAttributeFromDOMAttribute("target");
276 setFormElementProperties();
278 if (!("checked" in p_oAttributes)) {
280 p_oAttributes.checked = p_oElement.checked;
288 setFormElementProperties();
290 oRootNode = p_oElement.parentNode.parentNode;
292 if (Dom.hasClass(oRootNode, sClass + "-checked")) {
294 p_oAttributes.checked = true;
298 if (Dom.hasClass(oRootNode, sClass + "-disabled")) {
300 p_oAttributes.disabled = true;
304 p_oElement.removeAttribute("value");
306 p_oElement.setAttribute("type", "button");
312 p_oElement.removeAttribute("id");
313 p_oElement.removeAttribute("name");
315 if (!("tabindex" in p_oAttributes)) {
317 p_oAttributes.tabindex = p_oElement.tabIndex;
321 if (!("label" in p_oAttributes)) {
323 // Set the "label" property
325 sText = sSrcElementNodeName == "INPUT" ?
326 p_oElement.value : p_oElement.innerHTML;
329 if (sText && sText.length > 0) {
331 p_oAttributes.label = sText;
342 * @description Initializes the set of configuration attributes that are
343 * used to instantiate the button.
345 * @param {Object} Object representing the button's set of
346 * configuration attributes.
348 function initConfig(p_oConfig) {
350 var oAttributes = p_oConfig.attributes,
351 oSrcElement = oAttributes.srcelement,
352 sSrcElementNodeName = oSrcElement.nodeName.toUpperCase(),
356 if (sSrcElementNodeName == this.NODE_NAME) {
358 p_oConfig.element = oSrcElement;
359 p_oConfig.id = oSrcElement.id;
361 Dom.getElementsBy(function (p_oElement) {
363 switch (p_oElement.nodeName.toUpperCase()) {
369 setAttributesFromSrcElement.call(me, p_oElement,
376 }, "*", oSrcElement);
381 switch (sSrcElementNodeName) {
387 setAttributesFromSrcElement.call(this, oSrcElement,
402 YAHOO.widget.Button = function (p_oElement, p_oAttributes) {
404 if (!Overlay && YAHOO.widget.Overlay) {
406 Overlay = YAHOO.widget.Overlay;
411 if (!Menu && YAHOO.widget.Menu) {
413 Menu = YAHOO.widget.Menu;
418 var fnSuperClass = YAHOO.widget.Button.superclass.constructor,
423 if (arguments.length == 1 && !Lang.isString(p_oElement) && !p_oElement.nodeName) {
425 if (!p_oElement.id) {
427 p_oElement.id = Dom.generateId();
429 YAHOO.log("No value specified for the button's \"id\" " +
430 "attribute. Setting button id to \"" + p_oElement.id +
431 "\".", "info", this.toString());
435 YAHOO.log("No source HTML element. Building the button " +
436 "using the set of configuration attributes.", "info", this.toString());
438 fnSuperClass.call(this, (this.createButtonElement(p_oElement.type)), p_oElement);
443 oConfig = { element: null, attributes: (p_oAttributes || {}) };
446 if (Lang.isString(p_oElement)) {
448 oElement = Dom.get(p_oElement);
452 if (!oConfig.attributes.id) {
454 oConfig.attributes.id = p_oElement;
458 YAHOO.log("Building the button using an existing " +
459 "HTML element as a source element.", "info", this.toString());
462 oConfig.attributes.srcelement = oElement;
464 initConfig.call(this, oConfig);
467 if (!oConfig.element) {
469 YAHOO.log("Source element could not be used " +
470 "as is. Creating a new HTML element for " +
471 "the button.", "info", this.toString());
473 oConfig.element = this.createButtonElement(oConfig.attributes.type);
477 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
482 else if (p_oElement.nodeName) {
484 if (!oConfig.attributes.id) {
488 oConfig.attributes.id = p_oElement.id;
493 oConfig.attributes.id = Dom.generateId();
495 YAHOO.log("No value specified for the button's " +
496 "\"id\" attribute. Setting button id to \"" +
497 oConfig.attributes.id + "\".", "info", this.toString());
503 YAHOO.log("Building the button using an existing HTML " +
504 "element as a source element.", "info", this.toString());
507 oConfig.attributes.srcelement = p_oElement;
509 initConfig.call(this, oConfig);
512 if (!oConfig.element) {
514 YAHOO.log("Source element could not be used as is." +
515 " Creating a new HTML element for the button.",
516 "info", this.toString());
518 oConfig.element = this.createButtonElement(oConfig.attributes.type);
522 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
532 YAHOO.extend(YAHOO.widget.Button, YAHOO.util.Element, {
535 // Protected properties
540 * @description Object reference to the button's internal
541 * <code><a></code> or <code><button></code> element.
544 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
545 * level-one-html.html#ID-48250443">HTMLAnchorElement</a>|<a href="
546 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
547 * #ID-34812697">HTMLButtonElement</a>
554 * @description Object reference to the button's menu.
557 * @type {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|
558 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
564 * @property _hiddenFields
565 * @description Object reference to the <code><input></code>
566 * element, or array of HTML form elements used to represent the button
567 * when its parent form is submitted.
570 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
571 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array
577 * @property _onclickAttributeValue
578 * @description Object reference to the button's current value for the
579 * "onclick" configuration attribute.
584 _onclickAttributeValue: null,
588 * @property _activationKeyPressed
589 * @description Boolean indicating if the key(s) that toggle the button's
590 * "active" state have been pressed.
595 _activationKeyPressed: false,
599 * @property _activationButtonPressed
600 * @description Boolean indicating if the mouse button that toggles
601 * the button's "active" state has been pressed.
606 _activationButtonPressed: false,
610 * @property _hasKeyEventHandlers
611 * @description Boolean indicating if the button's "blur", "keydown" and
612 * "keyup" event handlers are assigned
617 _hasKeyEventHandlers: false,
621 * @property _hasMouseEventHandlers
622 * @description Boolean indicating if the button's "mouseout,"
623 * "mousedown," and "mouseup" event handlers are assigned
628 _hasMouseEventHandlers: false,
632 * @property _nOptionRegionX
633 * @description Number representing the X coordinate of the leftmost edge of the Button's
634 * option region. Applies only to Buttons of type "split".
646 * @property CLASS_NAME_PREFIX
647 * @description Prefix used for all class names applied to a Button.
652 CLASS_NAME_PREFIX: "yui-",
656 * @property NODE_NAME
657 * @description The name of the node to be used for the button's
667 * @property CHECK_ACTIVATION_KEYS
668 * @description Array of numbers representing keys that (when pressed)
669 * toggle the button's "checked" attribute.
674 CHECK_ACTIVATION_KEYS: [32],
678 * @property ACTIVATION_KEYS
679 * @description Array of numbers representing keys that (when presed)
680 * toggle the button's "active" state.
685 ACTIVATION_KEYS: [13, 32],
689 * @property OPTION_AREA_WIDTH
690 * @description Width (in pixels) of the area of a split button that
691 * when pressed will display a menu.
696 OPTION_AREA_WIDTH: 20,
700 * @property CSS_CLASS_NAME
701 * @description String representing the CSS class(es) to be applied to
702 * the button's root element.
707 CSS_CLASS_NAME: "button",
711 // Protected attribute setter methods
716 * @description Sets the value of the button's "type" attribute.
718 * @param {String} p_sType String indicating the value for the button's
721 _setType: function (p_sType) {
723 if (p_sType == "split") {
725 this.on("option", this._onOption);
734 * @description Sets the value of the button's "label" attribute.
736 * @param {String} p_sLabel String indicating the value for the button's
739 _setLabel: function (p_sLabel) {
741 this._button.innerHTML = p_sLabel;
745 Remove and add the default class name from the root element
746 for Gecko to ensure that the button shrinkwraps to the label.
747 Without this the button will not be rendered at the correct
748 width when the label changes. The most likely cause for this
749 bug is button's use of the Gecko-specific CSS display type of
750 "-moz-inline-box" to simulate "inline-block" supported by IE,
755 nGeckoVersion = UA.gecko;
758 if (nGeckoVersion && nGeckoVersion < 1.9 && Dom.inDocument(this.get("element"))) {
760 sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME);
762 this.removeClass(sClass);
764 Lang.later(0, this, this.addClass, sClass);
772 * @method _setTabIndex
773 * @description Sets the value of the button's "tabindex" attribute.
775 * @param {Number} p_nTabIndex Number indicating the value for the
776 * button's "tabindex" attribute.
778 _setTabIndex: function (p_nTabIndex) {
780 this._button.tabIndex = p_nTabIndex;
787 * @description Sets the value of the button's "title" attribute.
789 * @param {String} p_nTabIndex Number indicating the value for
790 * the button's "title" attribute.
792 _setTitle: function (p_sTitle) {
794 if (this.get("type") != "link") {
796 this._button.title = p_sTitle;
804 * @method _setDisabled
805 * @description Sets the value of the button's "disabled" attribute.
807 * @param {Boolean} p_bDisabled Boolean indicating the value for
808 * the button's "disabled" attribute.
810 _setDisabled: function (p_bDisabled) {
812 if (this.get("type") != "link") {
822 if (this.hasFocus()) {
828 this._button.setAttribute("disabled", "disabled");
830 this.addStateCSSClasses("disabled");
832 this.removeStateCSSClasses("hover");
833 this.removeStateCSSClasses("active");
834 this.removeStateCSSClasses("focus");
839 this._button.removeAttribute("disabled");
841 this.removeStateCSSClasses("disabled");
852 * @description Sets the value of the button's "href" attribute.
854 * @param {String} p_sHref String indicating the value for the button's
857 _setHref: function (p_sHref) {
859 if (this.get("type") == "link") {
861 this._button.href = p_sHref;
870 * @description Sets the value of the button's "target" attribute.
872 * @param {String} p_sTarget String indicating the value for the button's
873 * "target" attribute.
875 _setTarget: function (p_sTarget) {
877 if (this.get("type") == "link") {
879 this._button.setAttribute("target", p_sTarget);
887 * @method _setChecked
888 * @description Sets the value of the button's "target" attribute.
890 * @param {Boolean} p_bChecked Boolean indicating the value for
891 * the button's "checked" attribute.
893 _setChecked: function (p_bChecked) {
895 var sType = this.get("type");
897 if (sType == "checkbox" || sType == "radio") {
900 this.addStateCSSClasses("checked");
903 this.removeStateCSSClasses("checked");
913 * @description Sets the value of the button's "menu" attribute.
915 * @param {Object} p_oMenu Object indicating the value for the button's
918 _setMenu: function (p_oMenu) {
920 var bLazyLoad = this.get("lazyloadmenu"),
921 oButtonElement = this.get("element"),
925 Boolean indicating if the value of p_oMenu is an instance
926 of YAHOO.widget.Menu or YAHOO.widget.Overlay.
935 function onAppendTo() {
937 oMenu.render(oButtonElement.parentNode);
939 this.removeListener("appendTo", onAppendTo);
944 function setMenuContainer() {
946 oMenu.cfg.queueProperty("container", oButtonElement.parentNode);
948 this.removeListener("appendTo", setMenuContainer);
953 function initMenu() {
959 Dom.addClass(oMenu.element, this.get("menuclassname"));
960 Dom.addClass(oMenu.element, this.CLASS_NAME_PREFIX + this.get("type") + "-button-menu");
962 oMenu.showEvent.subscribe(this._onMenuShow, null, this);
963 oMenu.hideEvent.subscribe(this._onMenuHide, null, this);
964 oMenu.renderEvent.subscribe(this._onMenuRender, null, this);
967 if (Menu && oMenu instanceof Menu) {
971 oContainer = this.get("container");
975 oMenu.cfg.queueProperty("container", oContainer);
980 this.on("appendTo", setMenuContainer);
986 oMenu.cfg.queueProperty("clicktohide", false);
988 oMenu.keyDownEvent.subscribe(this._onMenuKeyDown, this, true);
989 oMenu.subscribe("click", this._onMenuClick, this, true);
991 this.on("selectedMenuItemChange", this._onSelectedMenuItemChange);
993 oSrcElement = oMenu.srcElement;
995 if (oSrcElement && oSrcElement.nodeName.toUpperCase() == "SELECT") {
997 oSrcElement.style.display = "none";
998 oSrcElement.parentNode.removeChild(oSrcElement);
1003 else if (Overlay && oMenu instanceof Overlay) {
1005 if (!m_oOverlayManager) {
1007 m_oOverlayManager = new YAHOO.widget.OverlayManager();
1011 m_oOverlayManager.register(oMenu);
1019 if (!bInstance && !bLazyLoad) {
1021 if (Dom.inDocument(oButtonElement)) {
1023 oMenu.render(oButtonElement.parentNode);
1028 this.on("appendTo", onAppendTo);
1043 sMenuCSSClassName = Menu.prototype.CSS_CLASS_NAME;
1047 if (p_oMenu && Menu && (p_oMenu instanceof Menu)) {
1052 initMenu.call(this);
1055 else if (Overlay && p_oMenu && (p_oMenu instanceof Overlay)) {
1060 oMenu.cfg.queueProperty("visible", false);
1062 initMenu.call(this);
1065 else if (Menu && Lang.isArray(p_oMenu)) {
1067 oMenu = new Menu(Dom.generateId(), { lazyload: bLazyLoad, itemdata: p_oMenu });
1071 this.on("appendTo", initMenu);
1074 else if (Lang.isString(p_oMenu)) {
1076 oMenuElement = Dom.get(p_oMenu);
1080 if (Menu && Dom.hasClass(oMenuElement, sMenuCSSClassName) ||
1081 oMenuElement.nodeName.toUpperCase() == "SELECT") {
1083 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1085 initMenu.call(this);
1090 oMenu = new Overlay(p_oMenu, { visible: false });
1092 initMenu.call(this);
1099 else if (p_oMenu && p_oMenu.nodeName) {
1101 if (Menu && Dom.hasClass(p_oMenu, sMenuCSSClassName) ||
1102 p_oMenu.nodeName.toUpperCase() == "SELECT") {
1104 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1106 initMenu.call(this);
1113 Dom.generateId(p_oMenu);
1117 oMenu = new Overlay(p_oMenu, { visible: false });
1119 initMenu.call(this);
1131 * @method _setOnClick
1132 * @description Sets the value of the button's "onclick" attribute.
1134 * @param {Object} p_oObject Object indicating the value for the button's
1135 * "onclick" attribute.
1137 _setOnClick: function (p_oObject) {
1140 Remove any existing listeners if a "click" event handler
1141 has already been specified.
1144 if (this._onclickAttributeValue &&
1145 (this._onclickAttributeValue != p_oObject)) {
1147 this.removeListener("click", this._onclickAttributeValue.fn);
1149 this._onclickAttributeValue = null;
1154 if (!this._onclickAttributeValue &&
1155 Lang.isObject(p_oObject) &&
1156 Lang.isFunction(p_oObject.fn)) {
1158 this.on("click", p_oObject.fn, p_oObject.obj, p_oObject.scope);
1160 this._onclickAttributeValue = p_oObject;
1168 // Protected methods
1173 * @method _isActivationKey
1174 * @description Determines if the specified keycode is one that toggles
1175 * the button's "active" state.
1177 * @param {Number} p_nKeyCode Number representing the keycode to
1181 _isActivationKey: function (p_nKeyCode) {
1183 var sType = this.get("type"),
1184 aKeyCodes = (sType == "checkbox" || sType == "radio") ?
1185 this.CHECK_ACTIVATION_KEYS : this.ACTIVATION_KEYS,
1187 nKeyCodes = aKeyCodes.length,
1192 if (nKeyCodes > 0) {
1198 if (p_nKeyCode == aKeyCodes[i]) {
1216 * @method _isSplitButtonOptionKey
1217 * @description Determines if the specified keycode is one that toggles
1218 * the display of the split button's menu.
1220 * @param {Event} p_oEvent Object representing the DOM event object
1221 * passed back by the event utility (YAHOO.util.Event).
1224 _isSplitButtonOptionKey: function (p_oEvent) {
1226 var bShowMenu = (Event.getCharCode(p_oEvent) == 40);
1229 var onKeyPress = function (p_oEvent) {
1231 Event.preventDefault(p_oEvent);
1233 this.removeListener("keypress", onKeyPress);
1238 // Prevent the browser from scrolling the window
1243 this.on("keypress", onKeyPress);
1247 Event.preventDefault(p_oEvent);
1256 * @method _addListenersToForm
1257 * @description Adds event handlers to the button's form.
1260 _addListenersToForm: function () {
1262 var oForm = this.getForm(),
1263 onFormKeyPress = YAHOO.widget.Button.onFormKeyPress,
1264 bHasKeyPressListener,
1273 Event.on(oForm, "reset", this._onFormReset, null, this);
1274 Event.on(oForm, "submit", this._onFormSubmit, null, this);
1276 oSrcElement = this.get("srcelement");
1279 if (this.get("type") == "submit" ||
1280 (oSrcElement && oSrcElement.type == "submit"))
1283 aListeners = Event.getListeners(oForm, "keypress");
1284 bHasKeyPressListener = false;
1288 nListeners = aListeners.length;
1290 if (nListeners > 0) {
1296 if (aListeners[i].fn == onFormKeyPress) {
1298 bHasKeyPressListener = true;
1311 if (!bHasKeyPressListener) {
1313 Event.on(oForm, "keypress", onFormKeyPress);
1327 * @description Shows the button's menu.
1329 * @param {Event} p_oEvent Object representing the DOM event object
1330 * passed back by the event utility (YAHOO.util.Event) that triggered
1331 * the display of the menu.
1333 _showMenu: function (p_oEvent) {
1335 if (YAHOO.widget.MenuManager) {
1336 YAHOO.widget.MenuManager.hideVisible();
1340 if (m_oOverlayManager) {
1341 m_oOverlayManager.hideAll();
1345 var oMenu = this._menu,
1346 aMenuAlignment = this.get("menualignment"),
1347 bFocusMenu = this.get("focusmenu"),
1351 if (this._renderedMenu) {
1353 oMenu.cfg.setProperty("context",
1354 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1356 oMenu.cfg.setProperty("preventcontextoverlap", true);
1357 oMenu.cfg.setProperty("constraintoviewport", true);
1362 oMenu.cfg.queueProperty("context",
1363 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1365 oMenu.cfg.queueProperty("preventcontextoverlap", true);
1366 oMenu.cfg.queueProperty("constraintoviewport", true);
1372 Refocus the Button before showing its Menu in case the call to
1373 YAHOO.widget.MenuManager.hideVisible() resulted in another element in the
1374 DOM being focused after another Menu was hidden.
1380 if (Menu && oMenu && (oMenu instanceof Menu)) {
1382 // Since Menus automatically focus themselves when made visible, temporarily
1383 // replace the Menu focus method so that the value of the Button's "focusmenu"
1384 // attribute determines if the Menu should be focus when made visible.
1386 fnFocusMethod = oMenu.focus;
1388 oMenu.focus = function () {};
1390 if (this._renderedMenu) {
1392 oMenu.cfg.setProperty("minscrollheight", this.get("menuminscrollheight"));
1393 oMenu.cfg.setProperty("maxheight", this.get("menumaxheight"));
1398 oMenu.cfg.queueProperty("minscrollheight", this.get("menuminscrollheight"));
1399 oMenu.cfg.queueProperty("maxheight", this.get("menumaxheight"));
1406 oMenu.focus = fnFocusMethod;
1412 Stop the propagation of the event so that the MenuManager
1413 doesn't blur the menu after it gets focus.
1416 if (p_oEvent.type == "mousedown") {
1417 Event.stopPropagation(p_oEvent);
1426 else if (Overlay && oMenu && (oMenu instanceof Overlay)) {
1428 if (!this._renderedMenu) {
1429 oMenu.render(this.get("element").parentNode);
1442 * @description Hides the button's menu.
1445 _hideMenu: function () {
1447 var oMenu = this._menu;
1460 // Protected event handlers
1464 * @method _onMouseOver
1465 * @description "mouseover" event handler for the button.
1467 * @param {Event} p_oEvent Object representing the DOM event object
1468 * passed back by the event utility (YAHOO.util.Event).
1470 _onMouseOver: function (p_oEvent) {
1472 var sType = this.get("type"),
1477 if (sType === "split") {
1479 oElement = this.get("element");
1481 (Dom.getX(oElement) + (oElement.offsetWidth - this.OPTION_AREA_WIDTH));
1483 this._nOptionRegionX = nOptionRegionX;
1488 if (!this._hasMouseEventHandlers) {
1490 if (sType === "split") {
1492 this.on("mousemove", this._onMouseMove);
1496 this.on("mouseout", this._onMouseOut);
1498 this._hasMouseEventHandlers = true;
1503 this.addStateCSSClasses("hover");
1506 if (sType === "split" && (Event.getPageX(p_oEvent) > nOptionRegionX)) {
1508 this.addStateCSSClasses("hoveroption");
1513 if (this._activationButtonPressed) {
1515 this.addStateCSSClasses("active");
1520 if (this._bOptionPressed) {
1522 this.addStateCSSClasses("activeoption");
1527 if (this._activationButtonPressed || this._bOptionPressed) {
1529 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1537 * @method _onMouseMove
1538 * @description "mousemove" event handler for the button.
1540 * @param {Event} p_oEvent Object representing the DOM event object
1541 * passed back by the event utility (YAHOO.util.Event).
1543 _onMouseMove: function (p_oEvent) {
1545 var nOptionRegionX = this._nOptionRegionX;
1547 if (nOptionRegionX) {
1549 if (Event.getPageX(p_oEvent) > nOptionRegionX) {
1551 this.addStateCSSClasses("hoveroption");
1556 this.removeStateCSSClasses("hoveroption");
1565 * @method _onMouseOut
1566 * @description "mouseout" event handler for the button.
1568 * @param {Event} p_oEvent Object representing the DOM event object
1569 * passed back by the event utility (YAHOO.util.Event).
1571 _onMouseOut: function (p_oEvent) {
1573 var sType = this.get("type");
1575 this.removeStateCSSClasses("hover");
1578 if (sType != "menu") {
1580 this.removeStateCSSClasses("active");
1585 if (this._activationButtonPressed || this._bOptionPressed) {
1587 Event.on(document, "mouseup", this._onDocumentMouseUp, null, this);
1592 if (sType === "split" && (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
1594 this.removeStateCSSClasses("hoveroption");
1602 * @method _onDocumentMouseUp
1603 * @description "mouseup" event handler for the button.
1605 * @param {Event} p_oEvent Object representing the DOM event object
1606 * passed back by the event utility (YAHOO.util.Event).
1608 _onDocumentMouseUp: function (p_oEvent) {
1610 this._activationButtonPressed = false;
1611 this._bOptionPressed = false;
1613 var sType = this.get("type"),
1617 if (sType == "menu" || sType == "split") {
1619 oTarget = Event.getTarget(p_oEvent);
1620 oMenuElement = this._menu.element;
1622 if (oTarget != oMenuElement &&
1623 !Dom.isAncestor(oMenuElement, oTarget)) {
1625 this.removeStateCSSClasses((sType == "menu" ?
1626 "active" : "activeoption"));
1634 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1640 * @method _onMouseDown
1641 * @description "mousedown" event handler for the button.
1643 * @param {Event} p_oEvent Object representing the DOM event object
1644 * passed back by the event utility (YAHOO.util.Event).
1646 _onMouseDown: function (p_oEvent) {
1652 function onMouseUp() {
1655 this.removeListener("mouseup", onMouseUp);
1660 if ((p_oEvent.which || p_oEvent.button) == 1) {
1663 if (!this.hasFocus()) {
1670 sType = this.get("type");
1673 if (sType == "split") {
1675 if (Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1677 this.fireEvent("option", p_oEvent);
1683 this.addStateCSSClasses("active");
1685 this._activationButtonPressed = true;
1690 else if (sType == "menu") {
1692 if (this.isActive()) {
1696 this._activationButtonPressed = false;
1701 this._showMenu(p_oEvent);
1703 this._activationButtonPressed = true;
1710 this.addStateCSSClasses("active");
1712 this._activationButtonPressed = true;
1718 if (sType == "split" || sType == "menu") {
1720 this._hideMenuTimer = Lang.later(250, this, this.on, ["mouseup", onMouseUp]);
1732 * @method _onMouseUp
1733 * @description "mouseup" event handler for the button.
1735 * @param {Event} p_oEvent Object representing the DOM event object
1736 * passed back by the event utility (YAHOO.util.Event).
1738 _onMouseUp: function (p_oEvent) {
1740 var sType = this.get("type"),
1741 oHideMenuTimer = this._hideMenuTimer,
1745 if (oHideMenuTimer) {
1747 oHideMenuTimer.cancel();
1752 if (sType == "checkbox" || sType == "radio") {
1754 this.set("checked", !(this.get("checked")));
1759 this._activationButtonPressed = false;
1762 if (sType != "menu") {
1764 this.removeStateCSSClasses("active");
1769 if (sType == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1782 * @description "focus" event handler for the button.
1784 * @param {Event} p_oEvent Object representing the DOM event object
1785 * passed back by the event utility (YAHOO.util.Event).
1787 _onFocus: function (p_oEvent) {
1791 this.addStateCSSClasses("focus");
1793 if (this._activationKeyPressed) {
1795 this.addStateCSSClasses("active");
1799 m_oFocusedButton = this;
1802 if (!this._hasKeyEventHandlers) {
1804 oElement = this._button;
1806 Event.on(oElement, "blur", this._onBlur, null, this);
1807 Event.on(oElement, "keydown", this._onKeyDown, null, this);
1808 Event.on(oElement, "keyup", this._onKeyUp, null, this);
1810 this._hasKeyEventHandlers = true;
1815 this.fireEvent("focus", p_oEvent);
1822 * @description "blur" event handler for the button.
1824 * @param {Event} p_oEvent Object representing the DOM event object
1825 * passed back by the event utility (YAHOO.util.Event).
1827 _onBlur: function (p_oEvent) {
1829 this.removeStateCSSClasses("focus");
1831 if (this.get("type") != "menu") {
1833 this.removeStateCSSClasses("active");
1837 if (this._activationKeyPressed) {
1839 Event.on(document, "keyup", this._onDocumentKeyUp, null, this);
1844 m_oFocusedButton = null;
1846 this.fireEvent("blur", p_oEvent);
1852 * @method _onDocumentKeyUp
1853 * @description "keyup" event handler for the document.
1855 * @param {Event} p_oEvent Object representing the DOM event object
1856 * passed back by the event utility (YAHOO.util.Event).
1858 _onDocumentKeyUp: function (p_oEvent) {
1860 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1862 this._activationKeyPressed = false;
1864 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
1872 * @method _onKeyDown
1873 * @description "keydown" event handler for the button.
1875 * @param {Event} p_oEvent Object representing the DOM event object
1876 * passed back by the event utility (YAHOO.util.Event).
1878 _onKeyDown: function (p_oEvent) {
1880 var oMenu = this._menu;
1883 if (this.get("type") == "split" &&
1884 this._isSplitButtonOptionKey(p_oEvent)) {
1886 this.fireEvent("option", p_oEvent);
1889 else if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1891 if (this.get("type") == "menu") {
1893 this._showMenu(p_oEvent);
1898 this._activationKeyPressed = true;
1900 this.addStateCSSClasses("active");
1907 if (oMenu && oMenu.cfg.getProperty("visible") &&
1908 Event.getCharCode(p_oEvent) == 27) {
1920 * @description "keyup" event handler for the button.
1922 * @param {Event} p_oEvent Object representing the DOM event object
1923 * passed back by the event utility (YAHOO.util.Event).
1925 _onKeyUp: function (p_oEvent) {
1929 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
1931 sType = this.get("type");
1933 if (sType == "checkbox" || sType == "radio") {
1935 this.set("checked", !(this.get("checked")));
1939 this._activationKeyPressed = false;
1941 if (this.get("type") != "menu") {
1943 this.removeStateCSSClasses("active");
1954 * @description "click" event handler for the button.
1956 * @param {Event} p_oEvent Object representing the DOM event object
1957 * passed back by the event utility (YAHOO.util.Event).
1959 _onClick: function (p_oEvent) {
1961 var sType = this.get("type"),
1971 if (p_oEvent.returnValue !== false) {
1981 oForm = this.getForm();
1994 if (this._nOptionRegionX > 0 &&
1995 (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
2004 oSrcElement = this.get("srcelement");
2006 if (oSrcElement && oSrcElement.type == "submit" &&
2007 p_oEvent.returnValue !== false) {
2025 * @method _onDblClick
2026 * @description "dblclick" event handler for the button.
2028 * @param {Event} p_oEvent Object representing the DOM event object
2029 * passed back by the event utility (YAHOO.util.Event).
2031 _onDblClick: function (p_oEvent) {
2033 var bReturnVal = true;
2035 if (this.get("type") == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
2047 * @method _onAppendTo
2048 * @description "appendTo" event handler for the button.
2050 * @param {Event} p_oEvent Object representing the DOM event object
2051 * passed back by the event utility (YAHOO.util.Event).
2053 _onAppendTo: function (p_oEvent) {
2056 It is necessary to call "_addListenersToForm" using
2057 "setTimeout" to make sure that the button's "form" property
2058 returns a node reference. Sometimes, if you try to get the
2059 reference immediately after appending the field, it is null.
2062 Lang.later(0, this, this._addListenersToForm);
2068 * @method _onFormReset
2069 * @description "reset" event handler for the button's form.
2071 * @param {Event} p_oEvent Object representing the DOM event
2072 * object passed back by the event utility (YAHOO.util.Event).
2074 _onFormReset: function (p_oEvent) {
2076 var sType = this.get("type"),
2079 if (sType == "checkbox" || sType == "radio") {
2081 this.resetValue("checked");
2086 if (Menu && oMenu && (oMenu instanceof Menu)) {
2088 this.resetValue("selectedMenuItem");
2096 * @method _onFormSubmit
2097 * @description "submit" event handler for the button's form.
2099 * @param {Event} p_oEvent Object representing the DOM event
2100 * object passed back by the event utility (YAHOO.util.Event).
2102 _onFormSubmit: function (p_oEvent) {
2104 this.createHiddenFields();
2110 * @method _onDocumentMouseDown
2111 * @description "mousedown" event handler for the document.
2113 * @param {Event} p_oEvent Object representing the DOM event object
2114 * passed back by the event utility (YAHOO.util.Event).
2116 _onDocumentMouseDown: function (p_oEvent) {
2118 var oTarget = Event.getTarget(p_oEvent),
2119 oButtonElement = this.get("element"),
2120 oMenuElement = this._menu.element;
2123 if (oTarget != oButtonElement &&
2124 !Dom.isAncestor(oButtonElement, oTarget) &&
2125 oTarget != oMenuElement &&
2126 !Dom.isAncestor(oMenuElement, oTarget)) {
2130 // In IE when the user mouses down on a focusable element
2131 // that element will be focused and become the "activeElement".
2132 // (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
2133 // However, there is a bug in IE where if there is a
2134 // positioned element with a focused descendant that is
2135 // hidden in response to the mousedown event, the target of
2136 // the mousedown event will appear to have focus, but will
2137 // not be set as the activeElement. This will result
2138 // in the element not firing key events, even though it
2139 // appears to have focus. The following call to "setActive"
2142 if (UA.ie && oTarget.focus) {
2143 oTarget.setActive();
2146 Event.removeListener(document, "mousedown",
2147 this._onDocumentMouseDown);
2156 * @description "option" event handler for the button.
2158 * @param {Event} p_oEvent Object representing the DOM event object
2159 * passed back by the event utility (YAHOO.util.Event).
2161 _onOption: function (p_oEvent) {
2163 if (this.hasClass(this.CLASS_NAME_PREFIX + "split-button-activeoption")) {
2167 this._bOptionPressed = false;
2172 this._showMenu(p_oEvent);
2174 this._bOptionPressed = true;
2182 * @method _onMenuShow
2183 * @description "show" event handler for the button's menu.
2185 * @param {String} p_sType String representing the name of the event
2188 _onMenuShow: function (p_sType) {
2190 Event.on(document, "mousedown", this._onDocumentMouseDown,
2193 var sState = (this.get("type") == "split") ? "activeoption" : "active";
2195 this.addStateCSSClasses(sState);
2201 * @method _onMenuHide
2202 * @description "hide" event handler for the button's menu.
2204 * @param {String} p_sType String representing the name of the event
2207 _onMenuHide: function (p_sType) {
2209 var sState = (this.get("type") == "split") ? "activeoption" : "active";
2211 this.removeStateCSSClasses(sState);
2214 if (this.get("type") == "split") {
2216 this._bOptionPressed = false;
2224 * @method _onMenuKeyDown
2225 * @description "keydown" event handler for the button's menu.
2227 * @param {String} p_sType String representing the name of the event
2229 * @param {Array} p_aArgs Array of arguments sent when the event
2232 _onMenuKeyDown: function (p_sType, p_aArgs) {
2234 var oEvent = p_aArgs[0];
2236 if (Event.getCharCode(oEvent) == 27) {
2240 if (this.get("type") == "split") {
2242 this._bOptionPressed = false;
2252 * @method _onMenuRender
2253 * @description "render" event handler for the button's menu.
2255 * @param {String} p_sType String representing the name of the
2256 * event thatwas fired.
2258 _onMenuRender: function (p_sType) {
2260 var oButtonElement = this.get("element"),
2261 oButtonParent = oButtonElement.parentNode,
2263 oMenuElement = oMenu.element,
2264 oSrcElement = oMenu.srcElement,
2268 if (oButtonParent != oMenuElement.parentNode) {
2270 oButtonParent.appendChild(oMenuElement);
2274 this._renderedMenu = true;
2276 // If the user has designated an <option> of the Menu's source
2277 // <select> element to be selected, sync the selectedIndex with
2278 // the "selectedMenuItem" Attribute.
2281 oSrcElement.nodeName.toLowerCase() === "select" &&
2282 oSrcElement.value) {
2285 oItem = oMenu.getItem(oSrcElement.selectedIndex);
2287 // Set the value of the "selectedMenuItem" attribute
2288 // silently since this is the initial set--synchronizing
2289 // the value of the source <SELECT> element in the DOM with
2290 // its corresponding Menu instance.
2292 this.set("selectedMenuItem", oItem, true);
2294 // Call the "_onSelectedMenuItemChange" method since the
2295 // attribute was set silently.
2297 this._onSelectedMenuItemChange({ newValue: oItem });
2306 * @method _onMenuClick
2307 * @description "click" event handler for the button's menu.
2309 * @param {String} p_sType String representing the name of the event
2311 * @param {Array} p_aArgs Array of arguments sent when the event
2314 _onMenuClick: function (p_sType, p_aArgs) {
2316 var oItem = p_aArgs[1],
2321 this.set("selectedMenuItem", oItem);
2323 oSrcElement = this.get("srcelement");
2325 if (oSrcElement && oSrcElement.type == "submit") {
2339 * @method _onSelectedMenuItemChange
2340 * @description "selectedMenuItemChange" event handler for the Button's
2341 * "selectedMenuItem" attribute.
2342 * @param {Event} event Object representing the DOM event object
2343 * passed back by the event utility (YAHOO.util.Event).
2345 _onSelectedMenuItemChange: function (event) {
2347 var oSelected = event.prevValue,
2348 oItem = event.newValue,
2349 sPrefix = this.CLASS_NAME_PREFIX;
2352 Dom.removeClass(oSelected.element, (sPrefix + "button-selectedmenuitem"));
2356 Dom.addClass(oItem.element, (sPrefix + "button-selectedmenuitem"));
2363 * @method _onLabelClick
2364 * @description "click" event handler for the Button's
2365 * <code><label></code> element.
2366 * @param {Event} event Object representing the DOM event object
2367 * passed back by the event utility (YAHOO.util.Event).
2369 _onLabelClick: function (event) {
2373 var sType = this.get("type");
2375 if (sType == "radio" || sType == "checkbox") {
2376 this.set("checked", (!this.get("checked")));
2386 * @method createButtonElement
2387 * @description Creates the button's HTML elements.
2388 * @param {String} p_sType String indicating the type of element
2390 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2391 * level-one-html.html#ID-58190037">HTMLElement</a>}
2393 createButtonElement: function (p_sType) {
2395 var sNodeName = this.NODE_NAME,
2396 oElement = document.createElement(sNodeName);
2398 oElement.innerHTML = "<" + sNodeName + " class=\"first-child\">" +
2399 (p_sType == "link" ? "<a></a>" :
2400 "<button type=\"button\"></button>") + "</" + sNodeName + ">";
2408 * @method addStateCSSClasses
2409 * @description Appends state-specific CSS classes to the button's root
2412 addStateCSSClasses: function (p_sState) {
2414 var sType = this.get("type"),
2415 sPrefix = this.CLASS_NAME_PREFIX;
2417 if (Lang.isString(p_sState)) {
2419 if (p_sState != "activeoption" && p_sState != "hoveroption") {
2421 this.addClass(sPrefix + this.CSS_CLASS_NAME + ("-" + p_sState));
2425 this.addClass(sPrefix + sType + ("-button-" + p_sState));
2433 * @method removeStateCSSClasses
2434 * @description Removes state-specific CSS classes to the button's root
2437 removeStateCSSClasses: function (p_sState) {
2439 var sType = this.get("type"),
2440 sPrefix = this.CLASS_NAME_PREFIX;
2442 if (Lang.isString(p_sState)) {
2444 this.removeClass(sPrefix + this.CSS_CLASS_NAME + ("-" + p_sState));
2445 this.removeClass(sPrefix + sType + ("-button-" + p_sState));
2453 * @method createHiddenFields
2454 * @description Creates the button's hidden form field and appends it
2455 * to its parent form.
2456 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2457 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
2459 createHiddenFields: function () {
2461 this.removeHiddenFields();
2463 var oForm = this.getForm(),
2475 bMenuSrcElementIsSelect = false;
2478 if (oForm && !this.get("disabled")) {
2480 sType = this.get("type");
2481 bCheckable = (sType == "checkbox" || sType == "radio");
2484 if ((bCheckable && this.get("checked")) || (m_oSubmitTrigger == this)) {
2486 YAHOO.log("Creating hidden field.", "info", this.toString());
2488 oButtonField = createInputElement((bCheckable ? sType : "hidden"),
2489 this.get("name"), this.get("value"), this.get("checked"));
2496 oButtonField.style.display = "none";
2500 oForm.appendChild(oButtonField);
2510 if (Menu && oMenu && (oMenu instanceof Menu)) {
2512 YAHOO.log("Creating hidden field for menu.", "info", this.toString());
2514 oMenuItem = this.get("selectedMenuItem");
2515 oMenuSrcElement = oMenu.srcElement;
2516 bMenuSrcElementIsSelect = (oMenuSrcElement &&
2517 oMenuSrcElement.nodeName.toUpperCase() == "SELECT");
2521 oValue = (oMenuItem.value === null || oMenuItem.value === "") ?
2522 oMenuItem.cfg.getProperty("text") : oMenuItem.value;
2524 sButtonName = this.get("name");
2527 if (bMenuSrcElementIsSelect) {
2529 sMenuFieldName = oMenuSrcElement.name;
2532 else if (sButtonName) {
2534 sMenuFieldName = (sButtonName + "_options");
2539 if (oValue && sMenuFieldName) {
2541 oMenuField = createInputElement("hidden", sMenuFieldName, oValue);
2542 oForm.appendChild(oMenuField);
2547 else if (bMenuSrcElementIsSelect) {
2549 oMenuField = oForm.appendChild(oMenuSrcElement);
2556 if (oButtonField && oMenuField) {
2558 this._hiddenFields = [oButtonField, oMenuField];
2561 else if (!oButtonField && oMenuField) {
2563 this._hiddenFields = oMenuField;
2566 else if (oButtonField && !oMenuField) {
2568 this._hiddenFields = oButtonField;
2572 oReturnVal = this._hiddenFields;
2582 * @method removeHiddenFields
2583 * @description Removes the button's hidden form field(s) from its
2586 removeHiddenFields: function () {
2588 var oField = this._hiddenFields,
2592 function removeChild(p_oElement) {
2594 if (Dom.inDocument(p_oElement)) {
2596 p_oElement.parentNode.removeChild(p_oElement);
2605 if (Lang.isArray(oField)) {
2607 nFields = oField.length;
2615 removeChild(oField[i]);
2625 removeChild(oField);
2629 this._hiddenFields = null;
2637 * @method submitForm
2638 * @description Submits the form to which the button belongs. Returns
2639 * true if the form was submitted successfully, false if the submission
2644 submitForm: function () {
2646 var oForm = this.getForm(),
2648 oSrcElement = this.get("srcelement"),
2651 Boolean indicating if the event fired successfully
2652 (was not cancelled by any handlers)
2655 bSubmitForm = false,
2662 if (this.get("type") == "submit" || (oSrcElement && oSrcElement.type == "submit")) {
2664 m_oSubmitTrigger = this;
2671 bSubmitForm = oForm.fireEvent("onsubmit");
2674 else { // Gecko, Opera, and Safari
2676 oEvent = document.createEvent("HTMLEvents");
2677 oEvent.initEvent("submit", true, true);
2679 bSubmitForm = oForm.dispatchEvent(oEvent);
2685 In IE and Safari, dispatching a "submit" event to a form
2686 WILL cause the form's "submit" event to fire, but WILL NOT
2687 submit the form. Therefore, we need to call the "submit"
2691 if ((UA.ie || UA.webkit) && bSubmitForm) {
2706 * @description The Button class's initialization method.
2707 * @param {String} p_oElement String specifying the id attribute of the
2708 * <code><input></code>, <code><button></code>,
2709 * <code><a></code>, or <code><span></code> element to
2710 * be used to create the button.
2711 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2712 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://
2713 * www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
2714 * #ID-34812697">HTMLButtonElement</a>|<a href="http://www.w3.org/TR
2715 * /2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-33759296">
2716 * HTMLElement</a>} p_oElement Object reference for the
2717 * <code><input></code>, <code><button></code>,
2718 * <code><a></code>, or <code><span></code> element to be
2719 * used to create the button.
2720 * @param {Object} p_oElement Object literal specifying a set of
2721 * configuration attributes used to create the button.
2722 * @param {Object} p_oAttributes Optional. Object literal specifying a
2723 * set of configuration attributes used to create the button.
2725 init: function (p_oElement, p_oAttributes) {
2727 var sNodeName = p_oAttributes.type == "link" ? "a" : "button",
2728 oSrcElement = p_oAttributes.srcelement,
2729 oButton = p_oElement.getElementsByTagName(sNodeName)[0],
2735 oInput = p_oElement.getElementsByTagName("input")[0];
2740 oButton = document.createElement("button");
2741 oButton.setAttribute("type", "button");
2743 oInput.parentNode.replaceChild(oButton, oInput);
2749 this._button = oButton;
2752 YAHOO.widget.Button.superclass.init.call(this, p_oElement, p_oAttributes);
2755 var sId = this.get("id"),
2756 sButtonId = sId + "-button";
2759 oButton.id = sButtonId;
2766 var hasLabel = function (element) {
2768 return (element.htmlFor === sId);
2773 var setLabel = function () {
2775 oLabel.setAttribute((UA.ie ? "htmlFor" : "for"), sButtonId);
2780 if (oSrcElement && this.get("type") != "link") {
2782 aLabels = Dom.getElementsBy(hasLabel, "label");
2784 if (Lang.isArray(aLabels) && aLabels.length > 0) {
2786 oLabel = aLabels[0];
2793 m_oButtons[sId] = this;
2795 var sPrefix = this.CLASS_NAME_PREFIX;
2797 this.addClass(sPrefix + this.CSS_CLASS_NAME);
2798 this.addClass(sPrefix + this.get("type") + "-button");
2800 Event.on(this._button, "focus", this._onFocus, null, this);
2801 this.on("mouseover", this._onMouseOver);
2802 this.on("mousedown", this._onMouseDown);
2803 this.on("mouseup", this._onMouseUp);
2804 this.on("click", this._onClick);
2806 // Need to reset the value of the "onclick" Attribute so that any
2807 // handlers registered via the "onclick" Attribute are fired after
2808 // Button's default "_onClick" listener.
2810 var fnOnClick = this.get("onclick");
2812 this.set("onclick", null);
2813 this.set("onclick", fnOnClick);
2815 this.on("dblclick", this._onDblClick);
2822 if (this.get("replaceLabel")) {
2824 this.set("label", oLabel.innerHTML);
2826 oParentNode = oLabel.parentNode;
2828 oParentNode.removeChild(oLabel);
2833 this.on("appendTo", setLabel);
2835 Event.on(oLabel, "click", this._onLabelClick, null, this);
2837 this._label = oLabel;
2843 this.on("appendTo", this._onAppendTo);
2847 var oContainer = this.get("container"),
2848 oElement = this.get("element"),
2849 bElInDoc = Dom.inDocument(oElement);
2854 if (oSrcElement && oSrcElement != oElement) {
2856 oParentNode = oSrcElement.parentNode;
2860 oParentNode.removeChild(oSrcElement);
2866 if (Lang.isString(oContainer)) {
2868 Event.onContentReady(oContainer, this.appendTo, oContainer, this);
2873 this.on("init", function () {
2875 Lang.later(0, this, this.appendTo, oContainer);
2882 else if (!bElInDoc && oSrcElement && oSrcElement != oElement) {
2884 oParentNode = oSrcElement.parentNode;
2888 this.fireEvent("beforeAppendTo", {
2889 type: "beforeAppendTo",
2893 oParentNode.replaceChild(oElement, oSrcElement);
2895 this.fireEvent("appendTo", {
2903 else if (this.get("type") != "link" && bElInDoc && oSrcElement &&
2904 oSrcElement == oElement) {
2906 this._addListenersToForm();
2910 YAHOO.log("Initialization completed.", "info", this.toString());
2913 this.fireEvent("init", {
2922 * @method initAttributes
2923 * @description Initializes all of the configuration attributes used to
2924 * create the button.
2925 * @param {Object} p_oAttributes Object literal specifying a set of
2926 * configuration attributes used to create the button.
2928 initAttributes: function (p_oAttributes) {
2930 var oAttributes = p_oAttributes || {};
2932 YAHOO.widget.Button.superclass.initAttributes.call(this,
2938 * @description String specifying the button's type. Possible
2939 * values are: "push," "link," "submit," "reset," "checkbox,"
2940 * "radio," "menu," and "split."
2945 this.setAttributeConfig("type", {
2947 value: (oAttributes.type || "push"),
2948 validator: Lang.isString,
2950 method: this._setType
2957 * @description String specifying the button's text label
2962 this.setAttributeConfig("label", {
2964 value: oAttributes.label,
2965 validator: Lang.isString,
2966 method: this._setLabel
2973 * @description Object specifying the value for the button.
2977 this.setAttributeConfig("value", {
2979 value: oAttributes.value
2986 * @description String specifying the name for the button.
2990 this.setAttributeConfig("name", {
2992 value: oAttributes.name,
2993 validator: Lang.isString
2999 * @attribute tabindex
3000 * @description Number specifying the tabindex for the button.
3004 this.setAttributeConfig("tabindex", {
3006 value: oAttributes.tabindex,
3007 validator: Lang.isNumber,
3008 method: this._setTabIndex
3015 * @description String specifying the title for the button.
3019 this.configureAttribute("title", {
3021 value: oAttributes.title,
3022 validator: Lang.isString,
3023 method: this._setTitle
3029 * @attribute disabled
3030 * @description Boolean indicating if the button should be disabled.
3031 * (Disabled buttons are dimmed and will not respond to user input
3032 * or fire events. Does not apply to button's of type "link.")
3036 this.setAttributeConfig("disabled", {
3038 value: (oAttributes.disabled || false),
3039 validator: Lang.isBoolean,
3040 method: this._setDisabled
3047 * @description String specifying the href for the button. Applies
3048 * only to buttons of type "link."
3051 this.setAttributeConfig("href", {
3053 value: oAttributes.href,
3054 validator: Lang.isString,
3055 method: this._setHref
3062 * @description String specifying the target for the button.
3063 * Applies only to buttons of type "link."
3066 this.setAttributeConfig("target", {
3068 value: oAttributes.target,
3069 validator: Lang.isString,
3070 method: this._setTarget
3076 * @attribute checked
3077 * @description Boolean indicating if the button is checked.
3078 * Applies only to buttons of type "radio" and "checkbox."
3082 this.setAttributeConfig("checked", {
3084 value: (oAttributes.checked || false),
3085 validator: Lang.isBoolean,
3086 method: this._setChecked
3092 * @attribute container
3093 * @description HTML element reference or string specifying the id
3094 * attribute of the HTML element that the button's markup should be
3096 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3097 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3101 this.setAttributeConfig("container", {
3103 value: oAttributes.container,
3110 * @attribute srcelement
3111 * @description Object reference to the HTML element (either
3112 * <code><input></code> or <code><span></code>)
3113 * used to create the button.
3114 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3115 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3119 this.setAttributeConfig("srcelement", {
3121 value: oAttributes.srcelement,
3129 * @description Object specifying the menu for the button.
3130 * The value can be one of the following:
3132 * <li>Object specifying a rendered <a href="YAHOO.widget.Menu.html">
3133 * YAHOO.widget.Menu</a> instance.</li>
3134 * <li>Object specifying a rendered <a href="YAHOO.widget.Overlay.html">
3135 * YAHOO.widget.Overlay</a> instance.</li>
3136 * <li>String specifying the id attribute of the <code><div>
3137 * </code> element used to create the menu. By default the menu
3138 * will be created as an instance of
3139 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>.
3140 * If the <a href="YAHOO.widget.Menu.html#CSS_CLASS_NAME">
3141 * default CSS class name for YAHOO.widget.Menu</a> is applied to
3142 * the <code><div></code> element, it will be created as an
3143 * instance of <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu
3144 * </a>.</li><li>String specifying the id attribute of the
3145 * <code><select></code> element used to create the menu.
3146 * </li><li>Object specifying the <code><div></code> element
3147 * used to create the menu.</li>
3148 * <li>Object specifying the <code><select></code> element
3149 * used to create the menu.</li>
3150 * <li>Array of object literals, each representing a set of
3151 * <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>
3152 * configuration attributes.</li>
3153 * <li>Array of strings representing the text labels for each menu
3154 * item in the menu.</li>
3156 * @type <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>|<a
3157 * href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|<a
3158 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3159 * one-html.html#ID-58190037">HTMLElement</a>|String|Array
3163 this.setAttributeConfig("menu", {
3166 method: this._setMenu,
3173 * @attribute lazyloadmenu
3174 * @description Boolean indicating the value to set for the
3175 * <a href="YAHOO.widget.Menu.html#lazyLoad">"lazyload"</a>
3176 * configuration property of the button's menu. Setting
3177 * "lazyloadmenu" to <code>true </code> will defer rendering of
3178 * the button's menu until the first time it is made visible.
3179 * If "lazyloadmenu" is set to <code>false</code>, the button's
3180 * menu will be rendered immediately if the button is in the
3181 * document, or in response to the button's "appendTo" event if
3182 * the button is not yet in the document. In either case, the
3183 * menu is rendered into the button's parent HTML element.
3184 * <em>This attribute does not apply if a
3185 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a> or
3186 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
3187 * instance is passed as the value of the button's "menu"
3188 * configuration attribute. <a href="YAHOO.widget.Menu.html">
3189 * YAHOO.widget.Menu</a> or <a href="YAHOO.widget.Overlay.html">
3190 * YAHOO.widget.Overlay</a> instances should be rendered before
3191 * being set as the value for the "menu" configuration
3197 this.setAttributeConfig("lazyloadmenu", {
3199 value: (oAttributes.lazyloadmenu === false ? false : true),
3200 validator: Lang.isBoolean,
3207 * @attribute menuclassname
3208 * @description String representing the CSS class name to be
3209 * applied to the root element of the button's menu.
3211 * @default "yui-button-menu"
3214 this.setAttributeConfig("menuclassname", {
3216 value: (oAttributes.menuclassname || (this.CLASS_NAME_PREFIX + "button-menu")),
3217 validator: Lang.isString,
3218 method: this._setMenuClassName,
3225 * @attribute menuminscrollheight
3226 * @description Number defining the minimum threshold for the "menumaxheight"
3227 * configuration attribute. When set this attribute is automatically applied
3232 this.setAttributeConfig("menuminscrollheight", {
3234 value: (oAttributes.menuminscrollheight || 90),
3235 validator: Lang.isNumber
3241 * @attribute menumaxheight
3242 * @description Number defining the maximum height (in pixels) for a menu's
3243 * body element (<code><div class="bd"<</code>). Once a menu's body
3244 * exceeds this height, the contents of the body are scrolled to maintain
3245 * this value. This value cannot be set lower than the value of the
3246 * "minscrollheight" configuration property.
3250 this.setAttributeConfig("menumaxheight", {
3252 value: (oAttributes.menumaxheight || 0),
3253 validator: Lang.isNumber
3259 * @attribute menualignment
3260 * @description Array defining how the Button's Menu is aligned to the Button.
3261 * The default value of ["tl", "bl"] aligns the Menu's top left corner to the Button's
3262 * bottom left corner.
3264 * @default ["tl", "bl"]
3266 this.setAttributeConfig("menualignment", {
3268 value: (oAttributes.menualignment || ["tl", "bl"]),
3269 validator: Lang.isArray
3275 * @attribute selectedMenuItem
3276 * @description Object representing the item in the button's menu
3277 * that is currently selected.
3278 * @type YAHOO.widget.MenuItem
3281 this.setAttributeConfig("selectedMenuItem", {
3289 * @attribute onclick
3290 * @description Object literal representing the code to be executed
3291 * when the button is clicked. Format:<br> <code> {<br>
3292 * <strong>fn:</strong> Function, // The handler to call
3293 * when the event fires.<br> <strong>obj:</strong> Object,
3294 * // An object to pass back to the handler.<br>
3295 * <strong>scope:</strong> Object // The object to use
3296 * for the scope of the handler.<br> } </code>
3300 this.setAttributeConfig("onclick", {
3302 value: oAttributes.onclick,
3303 method: this._setOnClick
3309 * @attribute focusmenu
3310 * @description Boolean indicating whether or not the button's menu
3311 * should be focused when it is made visible.
3315 this.setAttributeConfig("focusmenu", {
3317 value: (oAttributes.focusmenu === false ? false : true),
3318 validator: Lang.isBoolean
3324 * @attribute replaceLabel
3325 * @description Boolean indicating whether or not the text of the
3326 * button's <code><label></code> element should be used as
3327 * the source for the button's label configuration attribute and
3328 * removed from the DOM.
3332 this.setAttributeConfig("replaceLabel", {
3335 validator: Lang.isBoolean,
3345 * @description Causes the button to receive the focus and fires the
3346 * button's "focus" event.
3348 focus: function () {
3350 if (!this.get("disabled")) {
3352 this._button.focus();
3361 * @description Causes the button to lose focus and fires the button's
3366 if (!this.get("disabled")) {
3368 this._button.blur();
3377 * @description Returns a boolean indicating whether or not the button
3381 hasFocus: function () {
3383 return (m_oFocusedButton == this);
3390 * @description Returns a boolean indicating whether or not the button
3394 isActive: function () {
3396 return this.hasClass(this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME + "-active");
3403 * @description Returns a reference to the button's menu.
3404 * @return {<a href="YAHOO.widget.Overlay.html">
3405 * YAHOO.widget.Overlay</a>|<a
3406 * href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
3408 getMenu: function () {
3417 * @description Returns a reference to the button's parent form.
3418 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-
3419 * 20000929/level-one-html.html#ID-40002357">HTMLFormElement</a>}
3421 getForm: function () {
3423 var oButton = this._button,
3428 oForm = oButton.form;
3438 * @method getHiddenFields
3439 * @description Returns an <code><input></code> element or
3440 * array of form elements used to represent the button when its parent
3441 * form is submitted.
3442 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3443 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
3445 getHiddenFields: function () {
3447 return this._hiddenFields;
3454 * @description Removes the button's element from its parent element and
3455 * removes all event handlers.
3457 destroy: function () {
3459 YAHOO.log("Destroying ...", "info", this.toString());
3461 var oElement = this.get("element"),
3463 oLabel = this._label,
3469 YAHOO.log("Destroying menu.", "info", this.toString());
3471 if (m_oOverlayManager && m_oOverlayManager.find(oMenu)) {
3473 m_oOverlayManager.remove(oMenu);
3481 YAHOO.log("Removing DOM event listeners.", "info", this.toString());
3483 Event.purgeElement(oElement);
3484 Event.purgeElement(this._button);
3485 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
3486 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
3487 Event.removeListener(document, "mousedown", this._onDocumentMouseDown);
3492 Event.removeListener(oLabel, "click", this._onLabelClick);
3494 oParentNode = oLabel.parentNode;
3495 oParentNode.removeChild(oLabel);
3500 var oForm = this.getForm();
3504 Event.removeListener(oForm, "reset", this._onFormReset);
3505 Event.removeListener(oForm, "submit", this._onFormSubmit);
3509 YAHOO.log("Removing CustomEvent listeners.", "info", this.toString());
3511 this.unsubscribeAll();
3513 oParentNode = oElement.parentNode;
3517 oParentNode.removeChild(oElement);
3521 YAHOO.log("Removing from document.", "info", this.toString());
3523 delete m_oButtons[this.get("id")];
3525 var sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME);
3527 aButtons = Dom.getElementsByClassName(sClass,
3528 this.NODE_NAME, oForm);
3530 if (Lang.isArray(aButtons) && aButtons.length === 0) {
3532 Event.removeListener(oForm, "keypress",
3533 YAHOO.widget.Button.onFormKeyPress);
3537 YAHOO.log("Destroyed.", "info", this.toString());
3542 fireEvent: function (p_sType , p_aArgs) {
3544 var sType = arguments[0];
3546 // Disabled buttons should not respond to DOM events
3548 if (this.DOM_EVENTS[sType] && this.get("disabled")) {
3554 return YAHOO.widget.Button.superclass.fireEvent.apply(this, arguments);
3561 * @description Returns a string representing the button.
3564 toString: function () {
3566 return ("Button " + this.get("id"));
3574 * @method YAHOO.widget.Button.onFormKeyPress
3575 * @description "keypress" event handler for the button's form.
3576 * @param {Event} p_oEvent Object representing the DOM event object passed
3577 * back by the event utility (YAHOO.util.Event).
3579 YAHOO.widget.Button.onFormKeyPress = function (p_oEvent) {
3581 var oTarget = Event.getTarget(p_oEvent),
3582 nCharCode = Event.getCharCode(p_oEvent),
3583 sNodeName = oTarget.nodeName && oTarget.nodeName.toUpperCase(),
3584 sType = oTarget.type,
3587 Boolean indicating if the form contains any enabled or
3588 disabled YUI submit buttons
3591 bFormContainsYUIButtons = false,
3595 oYUISubmitButton, // The form's first, enabled YUI submit button
3598 The form's first, enabled HTML submit button that precedes any
3602 oPrecedingSubmitButton,
3607 function isSubmitButton(p_oElement) {
3612 switch (p_oElement.nodeName.toUpperCase()) {
3617 if (p_oElement.type == "submit" && !p_oElement.disabled) {
3619 if (!bFormContainsYUIButtons && !oPrecedingSubmitButton) {
3621 oPrecedingSubmitButton = p_oElement;
3632 sId = p_oElement.id;
3636 oButton = m_oButtons[sId];
3640 bFormContainsYUIButtons = true;
3642 if (!oButton.get("disabled")) {
3644 oSrcElement = oButton.get("srcelement");
3646 if (!oYUISubmitButton && (oButton.get("type") == "submit" ||
3647 (oSrcElement && oSrcElement.type == "submit"))) {
3649 oYUISubmitButton = oButton;
3666 if (nCharCode == 13 && ((sNodeName == "INPUT" && (sType == "text" ||
3667 sType == "password" || sType == "checkbox" || sType == "radio" ||
3668 sType == "file")) || sNodeName == "SELECT")) {
3670 Dom.getElementsBy(isSubmitButton, "*", this);
3673 if (oPrecedingSubmitButton) {
3676 Need to set focus to the first enabled submit button
3677 to make sure that IE includes its name and value
3678 in the form's data set.
3681 oPrecedingSubmitButton.focus();
3684 else if (!oPrecedingSubmitButton && oYUISubmitButton) {
3687 Need to call "preventDefault" to ensure that the form doesn't end up getting
3691 Event.preventDefault(p_oEvent);
3696 oYUISubmitButton.get("element").fireEvent("onclick");
3701 oEvent = document.createEvent("HTMLEvents");
3702 oEvent.initEvent("click", true, true);
3705 if (UA.gecko < 1.9) {
3707 oYUISubmitButton.fireEvent("click", oEvent);
3712 oYUISubmitButton.get("element").dispatchEvent(oEvent);
3726 * @method YAHOO.widget.Button.addHiddenFieldsToForm
3727 * @description Searches the specified form and adds hidden fields for
3728 * instances of YAHOO.widget.Button that are of type "radio," "checkbox,"
3729 * "menu," and "split."
3730 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3731 * one-html.html#ID-40002357">HTMLFormElement</a>} p_oForm Object reference
3732 * for the form to search.
3734 YAHOO.widget.Button.addHiddenFieldsToForm = function (p_oForm) {
3736 var proto = YAHOO.widget.Button.prototype,
3737 aButtons = Dom.getElementsByClassName(
3738 (proto.CLASS_NAME_PREFIX + proto.CSS_CLASS_NAME),
3742 nButtons = aButtons.length,
3749 YAHOO.log("Form contains " + nButtons + " YUI buttons.", "info", this.toString());
3751 for (i = 0; i < nButtons; i++) {
3753 sId = aButtons[i].id;
3757 oButton = m_oButtons[sId];
3761 oButton.createHiddenFields();
3775 * @method YAHOO.widget.Button.getButton
3776 * @description Returns a button with the specified id.
3777 * @param {String} p_sId String specifying the id of the root node of the
3778 * HTML element representing the button to be retrieved.
3779 * @return {YAHOO.widget.Button}
3781 YAHOO.widget.Button.getButton = function (p_sId) {
3783 return m_oButtons[p_sId];
3793 * @description Fires when the menu item receives focus. Passes back a
3794 * single object representing the original DOM event object passed back by
3795 * the event utility (YAHOO.util.Event) when the event was fired. See
3796 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3797 * for more information on listening for this event.
3798 * @type YAHOO.util.CustomEvent
3804 * @description Fires when the menu item loses the input focus. Passes back
3805 * a single object representing the original DOM event object passed back by
3806 * the event utility (YAHOO.util.Event) when the event was fired. See
3807 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for
3808 * more information on listening for this event.
3809 * @type YAHOO.util.CustomEvent
3815 * @description Fires when the user invokes the button's option. Passes
3816 * back a single object representing the original DOM event (either
3817 * "mousedown" or "keydown") that caused the "option" event to fire. See
3818 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3819 * for more information on listening for this event.
3820 * @type YAHOO.util.CustomEvent
3826 // Shorthard for utilities
3828 var Dom = YAHOO.util.Dom,
3829 Event = YAHOO.util.Event,
3831 Button = YAHOO.widget.Button,
3833 // Private collection of radio buttons
3840 * The ButtonGroup class creates a set of buttons that are mutually
3841 * exclusive; checking one button in the set will uncheck all others in the
3843 * @param {String} p_oElement String specifying the id attribute of the
3844 * <code><div></code> element of the button group.
3845 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3846 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
3847 * specifying the <code><div></code> element of the button group.
3848 * @param {Object} p_oElement Object literal specifying a set of
3849 * configuration attributes used to create the button group.
3850 * @param {Object} p_oAttributes Optional. Object literal specifying a set
3851 * of configuration attributes used to create the button group.
3852 * @namespace YAHOO.widget
3853 * @class ButtonGroup
3855 * @extends YAHOO.util.Element
3857 YAHOO.widget.ButtonGroup = function (p_oElement, p_oAttributes) {
3859 var fnSuperClass = YAHOO.widget.ButtonGroup.superclass.constructor,
3864 if (arguments.length == 1 && !Lang.isString(p_oElement) &&
3865 !p_oElement.nodeName) {
3867 if (!p_oElement.id) {
3869 sId = Dom.generateId();
3871 p_oElement.id = sId;
3873 YAHOO.log("No value specified for the button group's \"id\"" +
3874 " attribute. Setting button group id to \"" + sId + "\".",
3879 this.logger = new YAHOO.widget.LogWriter("ButtonGroup " + sId);
3881 this.logger.log("No source HTML element. Building the button " +
3882 "group using the set of configuration attributes.");
3884 fnSuperClass.call(this, (this._createGroupElement()), p_oElement);
3887 else if (Lang.isString(p_oElement)) {
3889 oElement = Dom.get(p_oElement);
3893 if (oElement.nodeName.toUpperCase() == this.NODE_NAME) {
3896 new YAHOO.widget.LogWriter("ButtonGroup " + p_oElement);
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();
3915 YAHOO.log("No value specified for the button group's" +
3916 " \"id\" attribute. Setting button group id " +
3917 "to \"" + p_oElement.id + "\".", "warn");
3922 new YAHOO.widget.LogWriter("ButtonGroup " + p_oElement.id);
3924 fnSuperClass.call(this, p_oElement, p_oAttributes);
3933 YAHOO.extend(YAHOO.widget.ButtonGroup, YAHOO.util.Element, {
3936 // Protected properties
3940 * @property _buttons
3941 * @description Array of buttons in the button group.
3954 * @property NODE_NAME
3955 * @description The name of the tag to be used for the button
3965 * @property CLASS_NAME_PREFIX
3966 * @description Prefix used for all class names applied to a ButtonGroup.
3971 CLASS_NAME_PREFIX: "yui-",
3975 * @property CSS_CLASS_NAME
3976 * @description String representing the CSS class(es) to be applied
3977 * to the button group's element.
3978 * @default "buttongroup"
3982 CSS_CLASS_NAME: "buttongroup",
3986 // Protected methods
3990 * @method _createGroupElement
3991 * @description Creates the button group's element.
3993 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3994 * level-one-html.html#ID-22445964">HTMLDivElement</a>}
3996 _createGroupElement: function () {
3998 var oElement = document.createElement(this.NODE_NAME);
4006 // Protected attribute setter methods
4010 * @method _setDisabled
4011 * @description Sets the value of the button groups's
4012 * "disabled" attribute.
4014 * @param {Boolean} p_bDisabled Boolean indicating the value for
4015 * the button group's "disabled" attribute.
4017 _setDisabled: function (p_bDisabled) {
4019 var nButtons = this.getCount(),
4028 this._buttons[i].set("disabled", p_bDisabled);
4039 // Protected event handlers
4043 * @method _onKeyDown
4044 * @description "keydown" event handler for the button group.
4046 * @param {Event} p_oEvent Object representing the DOM event object
4047 * passed back by the event utility (YAHOO.util.Event).
4049 _onKeyDown: function (p_oEvent) {
4051 var oTarget = Event.getTarget(p_oEvent),
4052 nCharCode = Event.getCharCode(p_oEvent),
4053 sId = oTarget.parentNode.parentNode.id,
4054 oButton = m_oButtons[sId],
4058 if (nCharCode == 37 || nCharCode == 38) {
4060 nIndex = (oButton.index === 0) ?
4061 (this._buttons.length - 1) : (oButton.index - 1);
4064 else if (nCharCode == 39 || nCharCode == 40) {
4066 nIndex = (oButton.index === (this._buttons.length - 1)) ?
4067 0 : (oButton.index + 1);
4075 this.getButton(nIndex).focus();
4083 * @method _onAppendTo
4084 * @description "appendTo" event handler for the button group.
4086 * @param {Event} p_oEvent Object representing the event that was fired.
4088 _onAppendTo: function (p_oEvent) {
4090 var aButtons = this._buttons,
4091 nButtons = aButtons.length,
4094 for (i = 0; i < nButtons; i++) {
4096 aButtons[i].appendTo(this.get("element"));
4104 * @method _onButtonCheckedChange
4105 * @description "checkedChange" event handler for each button in the
4108 * @param {Event} p_oEvent Object representing the event that was fired.
4109 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4110 * p_oButton Object representing the button that fired the event.
4112 _onButtonCheckedChange: function (p_oEvent, p_oButton) {
4114 var bChecked = p_oEvent.newValue,
4115 oCheckedButton = this.get("checkedButton");
4117 if (bChecked && oCheckedButton != p_oButton) {
4119 if (oCheckedButton) {
4121 oCheckedButton.set("checked", false, true);
4125 this.set("checkedButton", p_oButton);
4126 this.set("value", p_oButton.get("value"));
4129 else if (oCheckedButton && !oCheckedButton.set("checked")) {
4131 oCheckedButton.set("checked", true, true);
4144 * @description The ButtonGroup class's initialization method.
4145 * @param {String} p_oElement String specifying the id attribute of the
4146 * <code><div></code> element of the button group.
4147 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4148 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
4149 * specifying the <code><div></code> element of the button group.
4150 * @param {Object} p_oElement Object literal specifying a set of
4151 * configuration attributes used to create the button group.
4152 * @param {Object} p_oAttributes Optional. Object literal specifying a
4153 * set of configuration attributes used to create the button group.
4155 init: function (p_oElement, p_oAttributes) {
4159 YAHOO.widget.ButtonGroup.superclass.init.call(this, p_oElement,
4162 this.addClass(this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME);
4165 var sClass = (YAHOO.widget.Button.prototype.CLASS_NAME_PREFIX + "radio-button"),
4166 aButtons = this.getElementsByClassName(sClass);
4168 this.logger.log("Searching for child nodes with the class name " +
4169 sClass + " to add to the button group.");
4172 if (aButtons.length > 0) {
4174 this.logger.log("Found " + aButtons.length +
4175 " child nodes with the class name " + sClass +
4176 " Attempting to add to button group.");
4178 this.addButtons(aButtons);
4183 this.logger.log("Searching for child nodes with the type of " +
4184 " \"radio\" to add to the button group.");
4186 function isRadioButton(p_oElement) {
4188 return (p_oElement.type == "radio");
4193 Dom.getElementsBy(isRadioButton, "input", this.get("element"));
4196 if (aButtons.length > 0) {
4198 this.logger.log("Found " + aButtons.length + " child nodes" +
4199 " with the type of \"radio.\" Attempting to add to" +
4202 this.addButtons(aButtons);
4206 this.on("keydown", this._onKeyDown);
4207 this.on("appendTo", this._onAppendTo);
4210 var oContainer = this.get("container");
4214 if (Lang.isString(oContainer)) {
4216 Event.onContentReady(oContainer, function () {
4218 this.appendTo(oContainer);
4225 this.appendTo(oContainer);
4232 this.logger.log("Initialization completed.");
4238 * @method initAttributes
4239 * @description Initializes all of the configuration attributes used to
4240 * create the button group.
4241 * @param {Object} p_oAttributes Object literal specifying a set of
4242 * configuration attributes used to create the button group.
4244 initAttributes: function (p_oAttributes) {
4246 var oAttributes = p_oAttributes || {};
4248 YAHOO.widget.ButtonGroup.superclass.initAttributes.call(
4254 * @description String specifying the name for the button group.
4255 * This name will be applied to each button in the button group.
4259 this.setAttributeConfig("name", {
4261 value: oAttributes.name,
4262 validator: Lang.isString
4268 * @attribute disabled
4269 * @description Boolean indicating if the button group should be
4270 * disabled. Disabling the button group will disable each button
4271 * in the button group. Disabled buttons are dimmed and will not
4272 * respond to user input or fire events.
4276 this.setAttributeConfig("disabled", {
4278 value: (oAttributes.disabled || false),
4279 validator: Lang.isBoolean,
4280 method: this._setDisabled
4287 * @description Object specifying the value for the button group.
4291 this.setAttributeConfig("value", {
4293 value: oAttributes.value
4299 * @attribute container
4300 * @description HTML element reference or string specifying the id
4301 * attribute of the HTML element that the button group's markup
4302 * should be rendered into.
4303 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4304 * level-one-html.html#ID-58190037">HTMLElement</a>|String
4308 this.setAttributeConfig("container", {
4310 value: oAttributes.container,
4317 * @attribute checkedButton
4318 * @description Reference for the button in the button group that
4320 * @type {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4323 this.setAttributeConfig("checkedButton", {
4334 * @description Adds the button to the button group.
4335 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4336 * p_oButton Object reference for the <a href="YAHOO.widget.Button.html">
4337 * YAHOO.widget.Button</a> instance to be added to the button group.
4338 * @param {String} p_oButton String specifying the id attribute of the
4339 * <code><input></code> or <code><span></code> element
4340 * to be used to create the button to be added to the button group.
4341 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4342 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="
4343 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
4344 * ID-33759296">HTMLElement</a>} p_oButton Object reference for the
4345 * <code><input></code> or <code><span></code> element
4346 * to be used to create the button to be added to the button group.
4347 * @param {Object} p_oButton Object literal specifying a set of
4348 * <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4349 * configuration attributes used to configure the button to be added to
4351 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4353 addButton: function (p_oButton) {
4363 if (p_oButton instanceof Button &&
4364 p_oButton.get("type") == "radio") {
4366 oButton = p_oButton;
4369 else if (!Lang.isString(p_oButton) && !p_oButton.nodeName) {
4371 p_oButton.type = "radio";
4373 oButton = new Button(p_oButton);
4378 oButton = new Button(p_oButton, { type: "radio" });
4385 nIndex = this._buttons.length;
4386 sButtonName = oButton.get("name");
4387 sGroupName = this.get("name");
4389 oButton.index = nIndex;
4391 this._buttons[nIndex] = oButton;
4392 m_oButtons[oButton.get("id")] = oButton;
4395 if (sButtonName != sGroupName) {
4397 oButton.set("name", sGroupName);
4402 if (this.get("disabled")) {
4404 oButton.set("disabled", true);
4409 if (oButton.get("checked")) {
4411 this.set("checkedButton", oButton);
4416 oButtonElement = oButton.get("element");
4417 oGroupElement = this.get("element");
4419 if (oButtonElement.parentNode != oGroupElement) {
4421 oGroupElement.appendChild(oButtonElement);
4426 oButton.on("checkedChange",
4427 this._onButtonCheckedChange, oButton, this);
4429 this.logger.log("Button " + oButton.get("id") + " added.");
4439 * @method addButtons
4440 * @description Adds the array of buttons to the button group.
4441 * @param {Array} p_aButtons Array of <a href="YAHOO.widget.Button.html">
4442 * YAHOO.widget.Button</a> instances to be added
4443 * to the button group.
4444 * @param {Array} p_aButtons Array of strings specifying the id
4445 * attribute of the <code><input></code> or <code><span>
4446 * </code> elements to be used to create the buttons to be added to the
4448 * @param {Array} p_aButtons Array of object references for the
4449 * <code><input></code> or <code><span></code> elements
4450 * to be used to create the buttons to be added to the button group.
4451 * @param {Array} p_aButtons Array of object literals, each containing
4452 * a set of <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4453 * configuration attributes used to configure each button to be added
4454 * to the button group.
4457 addButtons: function (p_aButtons) {
4464 if (Lang.isArray(p_aButtons)) {
4466 nButtons = p_aButtons.length;
4471 for (i = 0; i < nButtons; i++) {
4473 oButton = this.addButton(p_aButtons[i]);
4477 aButtons[aButtons.length] = oButton;
4493 * @method removeButton
4494 * @description Removes the button at the specified index from the
4496 * @param {Number} p_nIndex Number specifying the index of the button
4497 * to be removed from the button group.
4499 removeButton: function (p_nIndex) {
4501 var oButton = this.getButton(p_nIndex),
4507 this.logger.log("Removing button " + oButton.get("id") + ".");
4509 this._buttons.splice(p_nIndex, 1);
4510 delete m_oButtons[oButton.get("id")];
4512 oButton.removeListener("checkedChange",
4513 this._onButtonCheckedChange);
4518 nButtons = this._buttons.length;
4522 i = this._buttons.length - 1;
4526 this._buttons[i].index = i;
4533 this.logger.log("Button " + oButton.get("id") + " removed.");
4542 * @description Returns the button at the specified index.
4543 * @param {Number} p_nIndex The index of the button to retrieve from the
4545 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4547 getButton: function (p_nIndex) {
4549 return this._buttons[p_nIndex];
4555 * @method getButtons
4556 * @description Returns an array of the buttons in the button group.
4559 getButtons: function () {
4561 return this._buttons;
4568 * @description Returns the number of buttons in the button group.
4571 getCount: function () {
4573 return this._buttons.length;
4580 * @description Sets focus to the button at the specified index.
4581 * @param {Number} p_nIndex Number indicating the index of the button
4584 focus: function (p_nIndex) {
4590 if (Lang.isNumber(p_nIndex)) {
4592 oButton = this._buttons[p_nIndex];
4603 nButtons = this.getCount();
4605 for (i = 0; i < nButtons; i++) {
4607 oButton = this._buttons[i];
4609 if (!oButton.get("disabled")) {
4625 * @description Checks the button at the specified index.
4626 * @param {Number} p_nIndex Number indicating the index of the button
4629 check: function (p_nIndex) {
4631 var oButton = this.getButton(p_nIndex);
4635 oButton.set("checked", true);
4644 * @description Removes the button group's element from its parent
4645 * element and removes all event handlers.
4647 destroy: function () {
4649 this.logger.log("Destroying...");
4651 var nButtons = this._buttons.length,
4652 oElement = this.get("element"),
4653 oParentNode = oElement.parentNode,
4658 i = this._buttons.length - 1;
4662 this._buttons[i].destroy();
4669 this.logger.log("Removing DOM event handlers.");
4671 Event.purgeElement(oElement);
4673 this.logger.log("Removing from document.");
4675 oParentNode.removeChild(oElement);
4682 * @description Returns a string representing the button group.
4685 toString: function () {
4687 return ("ButtonGroup " + this.get("id"));
4694 YAHOO.register("button", YAHOO.widget.Button, {version: "2.8.0r4", build: "2449"});