2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
9 * @description <p>The Button Control enables the creation of rich, graphical
10 * buttons that function like traditional HTML form buttons. <em>Unlike</em>
11 * traditional HTML form buttons, buttons created with the Button Control can have
12 * a label that is different from its value. With the inclusion of the optional
13 * <a href="module_menu.html">Menu Control</a>, the Button Control can also be
14 * used to create menu buttons and split buttons, controls that are not
15 * available natively in HTML. The Button Control can also be thought of as a
16 * way to create more visually engaging implementations of the browser's
17 * default radio-button and check-box controls.</p>
18 * <p>The Button Control supports the following types:</p>
21 * <dd>Basic push button that can execute a user-specified command when
24 * <dd>Navigates to a specified url when pressed.</dd>
26 * <dd>Submits the parent form when pressed.</dd>
28 * <dd>Resets the parent form when pressed.</dd>
30 * <dd>Maintains a "checked" state that can be toggled on and off.</dd>
32 * <dd>Maintains a "checked" state that can be toggled on and off. Use with
33 * the ButtonGroup class to create a set of controls that are mutually
34 * exclusive; checking one button in the set will uncheck all others in
37 * <dd>When pressed will show/hide a menu.</dd>
39 * <dd>Can execute a user-specified command or display a menu when pressed.</dd>
42 * @namespace YAHOO.widget
43 * @requires yahoo, dom, element, event
44 * @optional container, menu
52 * The Button class creates a rich, graphical button.
53 * @param {String} p_oElement String specifying the id attribute of the
54 * <code><input></code>, <code><button></code>,
55 * <code><a></code>, or <code><span></code> element to
56 * be used to create the button.
57 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
58 * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org
59 * /TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-34812697">
60 * HTMLButtonElement</a>|<a href="
61 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
62 * ID-33759296">HTMLElement</a>} p_oElement Object reference for the
63 * <code><input></code>, <code><button></code>,
64 * <code><a></code>, or <code><span></code> element to be
65 * used to create the button.
66 * @param {Object} p_oElement Object literal specifying a set of
67 * configuration attributes used to create the button.
68 * @param {Object} p_oAttributes Optional. Object literal specifying a set
69 * of configuration attributes used to create the button.
70 * @namespace YAHOO.widget
73 * @extends YAHOO.util.Element
78 // Shorthard for utilities
80 var Dom = YAHOO.util.Dom,
81 Event = YAHOO.util.Event,
84 Overlay = YAHOO.widget.Overlay,
85 Menu = YAHOO.widget.Menu,
88 // Private member variables
90 m_oButtons = {}, // Collection of all Button instances
91 m_oOverlayManager = null, // YAHOO.widget.OverlayManager instance
92 m_oSubmitTrigger = null, // The button that submitted the form
93 m_oFocusedButton = null; // The button that has focus
102 * @method createInputElement
103 * @description Creates an <code><input></code> element of the
106 * @param {String} p_sType String specifying the type of
107 * <code><input></code> element to create.
108 * @param {String} p_sName String specifying the name of
109 * <code><input></code> element to create.
110 * @param {String} p_sValue String specifying the value of
111 * <code><input></code> element to create.
112 * @param {String} p_bChecked Boolean specifying if the
113 * <code><input></code> element is to be checked.
114 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
115 * one-html.html#ID-6043025">HTMLInputElement</a>}
117 function createInputElement(p_sType, p_sName, p_sValue, p_bChecked) {
122 if (Lang.isString(p_sType) && Lang.isString(p_sName)) {
127 For IE it is necessary to create the element with the
128 "type," "name," "value," and "checked" properties set all
132 sInput = "<input type=\"" + p_sType + "\" name=\"" +
137 sInput += " checked";
143 oInput = document.createElement(sInput);
148 oInput = document.createElement("input");
149 oInput.name = p_sName;
150 oInput.type = p_sType;
154 oInput.checked = true;
160 oInput.value = p_sValue;
170 * @method setAttributesFromSrcElement
171 * @description Gets the values for all the attributes of the source element
172 * (either <code><input></code> or <code><a></code>) that
173 * map to Button configuration attributes and sets them into a collection
174 * that is passed to the Button constructor.
176 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
177 * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org/
178 * TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-
179 * 48250443">HTMLAnchorElement</a>} p_oElement Object reference to the HTML
180 * element (either <code><input></code> or <code><span>
181 * </code>) used to create the button.
182 * @param {Object} p_oAttributes Object reference for the collection of
183 * configuration attributes used to create the button.
185 function setAttributesFromSrcElement(p_oElement, p_oAttributes) {
187 var sSrcElementNodeName = p_oElement.nodeName.toUpperCase(),
195 * @method setAttributeFromDOMAttribute
196 * @description Gets the value of the specified DOM attribute and sets it
197 * into the collection of configuration attributes used to configure
200 * @param {String} p_sAttribute String representing the name of the
201 * attribute to retrieve from the DOM element.
203 function setAttributeFromDOMAttribute(p_sAttribute) {
205 if (!(p_sAttribute in p_oAttributes)) {
208 Need to use "getAttributeNode" instead of "getAttribute"
209 because using "getAttribute," IE will return the innerText
210 of a <code><button></code> for the value attribute
211 rather than the value of the "value" attribute.
214 oAttribute = p_oElement.getAttributeNode(p_sAttribute);
217 if (oAttribute && ("value" in oAttribute)) {
219 YAHOO.log("Setting attribute \"" + p_sAttribute +
220 "\" using source element's attribute value of \"" +
221 oAttribute.value + "\"", "info", me.toString());
223 p_oAttributes[p_sAttribute] = oAttribute.value;
233 * @method setFormElementProperties
234 * @description Gets the value of the attributes from the form element
235 * and sets them into the collection of configuration attributes used to
236 * configure the button.
239 function setFormElementProperties() {
241 setAttributeFromDOMAttribute("type");
243 if (p_oAttributes.type == "button") {
245 p_oAttributes.type = "push";
249 if (!("disabled" in p_oAttributes)) {
251 p_oAttributes.disabled = p_oElement.disabled;
255 setAttributeFromDOMAttribute("name");
256 setAttributeFromDOMAttribute("value");
257 setAttributeFromDOMAttribute("title");
262 switch (sSrcElementNodeName) {
266 p_oAttributes.type = "link";
268 setAttributeFromDOMAttribute("href");
269 setAttributeFromDOMAttribute("target");
275 setFormElementProperties();
277 if (!("checked" in p_oAttributes)) {
279 p_oAttributes.checked = p_oElement.checked;
287 setFormElementProperties();
289 oRootNode = p_oElement.parentNode.parentNode;
291 if (Dom.hasClass(oRootNode, this.CSS_CLASS_NAME + "-checked")) {
293 p_oAttributes.checked = true;
297 if (Dom.hasClass(oRootNode, this.CSS_CLASS_NAME + "-disabled")) {
299 p_oAttributes.disabled = true;
303 p_oElement.removeAttribute("value");
305 p_oElement.setAttribute("type", "button");
311 p_oElement.removeAttribute("id");
312 p_oElement.removeAttribute("name");
314 if (!("tabindex" in p_oAttributes)) {
316 p_oAttributes.tabindex = p_oElement.tabIndex;
320 if (!("label" in p_oAttributes)) {
322 // Set the "label" property
324 sText = sSrcElementNodeName == "INPUT" ?
325 p_oElement.value : p_oElement.innerHTML;
328 if (sText && sText.length > 0) {
330 p_oAttributes.label = sText;
341 * @description Initializes the set of configuration attributes that are
342 * used to instantiate the button.
344 * @param {Object} Object representing the button's set of
345 * configuration attributes.
347 function initConfig(p_oConfig) {
349 var oAttributes = p_oConfig.attributes,
350 oSrcElement = oAttributes.srcelement,
351 sSrcElementNodeName = oSrcElement.nodeName.toUpperCase(),
355 if (sSrcElementNodeName == this.NODE_NAME) {
357 p_oConfig.element = oSrcElement;
358 p_oConfig.id = oSrcElement.id;
360 Dom.getElementsBy(function (p_oElement) {
362 switch (p_oElement.nodeName.toUpperCase()) {
368 setAttributesFromSrcElement.call(me, p_oElement,
375 }, "*", oSrcElement);
380 switch (sSrcElementNodeName) {
386 setAttributesFromSrcElement.call(this, oSrcElement,
401 YAHOO.widget.Button = function (p_oElement, p_oAttributes) {
403 if (!Overlay && YAHOO.widget.Overlay) {
405 Overlay = YAHOO.widget.Overlay;
410 if (!Menu && YAHOO.widget.Menu) {
412 Menu = YAHOO.widget.Menu;
417 var fnSuperClass = YAHOO.widget.Button.superclass.constructor,
422 if (arguments.length == 1 && !Lang.isString(p_oElement) && !p_oElement.nodeName) {
424 if (!p_oElement.id) {
426 p_oElement.id = Dom.generateId();
428 YAHOO.log("No value specified for the button's \"id\" " +
429 "attribute. Setting button id to \"" + p_oElement.id +
430 "\".", "info", this.toString());
434 YAHOO.log("No source HTML element. Building the button " +
435 "using the set of configuration attributes.", "info", this.toString());
437 fnSuperClass.call(this, (this.createButtonElement(p_oElement.type)), p_oElement);
442 oConfig = { element: null, attributes: (p_oAttributes || {}) };
445 if (Lang.isString(p_oElement)) {
447 oElement = Dom.get(p_oElement);
451 if (!oConfig.attributes.id) {
453 oConfig.attributes.id = p_oElement;
457 YAHOO.log("Building the button using an existing " +
458 "HTML element as a source element.", "info", this.toString());
461 oConfig.attributes.srcelement = oElement;
463 initConfig.call(this, oConfig);
466 if (!oConfig.element) {
468 YAHOO.log("Source element could not be used " +
469 "as is. Creating a new HTML element for " +
470 "the button.", "info", this.toString());
472 oConfig.element = this.createButtonElement(oConfig.attributes.type);
476 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
481 else if (p_oElement.nodeName) {
483 if (!oConfig.attributes.id) {
487 oConfig.attributes.id = p_oElement.id;
492 oConfig.attributes.id = Dom.generateId();
494 YAHOO.log("No value specified for the button's " +
495 "\"id\" attribute. Setting button id to \"" +
496 oConfig.attributes.id + "\".", "info", this.toString());
502 YAHOO.log("Building the button using an existing HTML " +
503 "element as a source element.", "info", this.toString());
506 oConfig.attributes.srcelement = p_oElement;
508 initConfig.call(this, oConfig);
511 if (!oConfig.element) {
513 YAHOO.log("Source element could not be used as is." +
514 " Creating a new HTML element for the button.",
515 "info", this.toString());
517 oConfig.element = this.createButtonElement(oConfig.attributes.type);
521 fnSuperClass.call(this, oConfig.element, oConfig.attributes);
531 YAHOO.extend(YAHOO.widget.Button, YAHOO.util.Element, {
534 // Protected properties
539 * @description Object reference to the button's internal
540 * <code><a></code> or <code><button></code> element.
543 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
544 * level-one-html.html#ID-48250443">HTMLAnchorElement</a>|<a href="
545 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
546 * #ID-34812697">HTMLButtonElement</a>
553 * @description Object reference to the button's menu.
556 * @type {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|
557 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
563 * @property _hiddenFields
564 * @description Object reference to the <code><input></code>
565 * element, or array of HTML form elements used to represent the button
566 * when its parent form is submitted.
569 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
570 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array
576 * @property _onclickAttributeValue
577 * @description Object reference to the button's current value for the
578 * "onclick" configuration attribute.
583 _onclickAttributeValue: null,
587 * @property _activationKeyPressed
588 * @description Boolean indicating if the key(s) that toggle the button's
589 * "active" state have been pressed.
594 _activationKeyPressed: false,
598 * @property _activationButtonPressed
599 * @description Boolean indicating if the mouse button that toggles
600 * the button's "active" state has been pressed.
605 _activationButtonPressed: false,
609 * @property _hasKeyEventHandlers
610 * @description Boolean indicating if the button's "blur", "keydown" and
611 * "keyup" event handlers are assigned
616 _hasKeyEventHandlers: false,
620 * @property _hasMouseEventHandlers
621 * @description Boolean indicating if the button's "mouseout,"
622 * "mousedown," and "mouseup" event handlers are assigned
627 _hasMouseEventHandlers: false,
631 * @property _nOptionRegionX
632 * @description Number representing the X coordinate of the leftmost edge of the Button's
633 * option region. Applies only to Buttons of type "split".
646 * @property NODE_NAME
647 * @description The name of the node to be used for the button's
657 * @property CHECK_ACTIVATION_KEYS
658 * @description Array of numbers representing keys that (when pressed)
659 * toggle the button's "checked" attribute.
664 CHECK_ACTIVATION_KEYS: [32],
668 * @property ACTIVATION_KEYS
669 * @description Array of numbers representing keys that (when presed)
670 * toggle the button's "active" state.
675 ACTIVATION_KEYS: [13, 32],
679 * @property OPTION_AREA_WIDTH
680 * @description Width (in pixels) of the area of a split button that
681 * when pressed will display a menu.
686 OPTION_AREA_WIDTH: 20,
690 * @property CSS_CLASS_NAME
691 * @description String representing the CSS class(es) to be applied to
692 * the button's root element.
693 * @default "yui-button"
697 CSS_CLASS_NAME: "yui-button",
701 * @property RADIO_DEFAULT_TITLE
702 * @description String representing the default title applied to buttons
704 * @default "Unchecked. Click to check."
708 RADIO_DEFAULT_TITLE: "Unchecked. Click to check.",
712 * @property RADIO_CHECKED_TITLE
713 * @description String representing the title applied to buttons of
714 * type "radio" when checked.
715 * @default "Checked. Click another button to uncheck"
719 RADIO_CHECKED_TITLE: "Checked. Click another button to uncheck",
723 * @property CHECKBOX_DEFAULT_TITLE
724 * @description String representing the default title applied to
725 * buttons of type "checkbox."
726 * @default "Unchecked. Click to check."
730 CHECKBOX_DEFAULT_TITLE: "Unchecked. Click to check.",
734 * @property CHECKBOX_CHECKED_TITLE
735 * @description String representing the title applied to buttons of type
736 * "checkbox" when checked.
737 * @default "Checked. Click to uncheck."
741 CHECKBOX_CHECKED_TITLE: "Checked. Click to uncheck.",
745 * @property MENUBUTTON_DEFAULT_TITLE
746 * @description String representing the default title applied to
747 * buttons of type "menu."
748 * @default "Menu collapsed. Click to expand."
752 MENUBUTTON_DEFAULT_TITLE: "Menu collapsed. Click to expand.",
756 * @property MENUBUTTON_MENU_VISIBLE_TITLE
757 * @description String representing the title applied to buttons of type
758 * "menu" when the button's menu is visible.
759 * @default "Menu expanded. Click or press Esc to collapse."
763 MENUBUTTON_MENU_VISIBLE_TITLE:
764 "Menu expanded. Click or press Esc to collapse.",
768 * @property SPLITBUTTON_DEFAULT_TITLE
769 * @description String representing the default title applied to
770 * buttons of type "split."
771 * @default "Menu collapsed. Click inside option region or press
772 * Ctrl + Shift + M to show the menu."
776 SPLITBUTTON_DEFAULT_TITLE: ("Menu collapsed. Click inside option " +
777 "region or press down arrow key to show the menu."),
781 * @property SPLITBUTTON_OPTION_VISIBLE_TITLE
782 * @description String representing the title applied to buttons of type
783 * "split" when the button's menu is visible.
784 * @default "Menu expanded. Press Esc or Ctrl + Shift + M to hide
789 SPLITBUTTON_OPTION_VISIBLE_TITLE:
790 "Menu expanded. Press Esc to hide the menu.",
794 * @property SUBMIT_TITLE
795 * @description String representing the title applied to buttons of
797 * @default "Click to submit form."
801 SUBMIT_TITLE: "Click to submit form.",
805 // Protected attribute setter methods
810 * @description Sets the value of the button's "type" attribute.
812 * @param {String} p_sType String indicating the value for the button's
815 _setType: function (p_sType) {
817 if (p_sType == "split") {
819 this.on("option", this._onOption);
828 * @description Sets the value of the button's "label" attribute.
830 * @param {String} p_sLabel String indicating the value for the button's
833 _setLabel: function (p_sLabel) {
835 this._button.innerHTML = p_sLabel;
839 Remove and add the default class name from the root element
840 for Gecko to ensure that the button shrinkwraps to the label.
841 Without this the button will not be rendered at the correct
842 width when the label changes. The most likely cause for this
843 bug is button's use of the Gecko-specific CSS display type of
844 "-moz-inline-box" to simulate "inline-block" supported by IE,
849 nGeckoVersion = UA.gecko;
852 if (nGeckoVersion && nGeckoVersion < 1.9 && Dom.inDocument(this.get("element"))) {
854 sClass = this.CSS_CLASS_NAME;
856 this.removeClass(sClass);
858 Lang.later(0, this, this.addClass, sClass);
866 * @method _setTabIndex
867 * @description Sets the value of the button's "tabindex" attribute.
869 * @param {Number} p_nTabIndex Number indicating the value for the
870 * button's "tabindex" attribute.
872 _setTabIndex: function (p_nTabIndex) {
874 this._button.tabIndex = p_nTabIndex;
881 * @description Sets the value of the button's "title" attribute.
883 * @param {String} p_nTabIndex Number indicating the value for
884 * the button's "title" attribute.
886 _setTitle: function (p_sTitle) {
888 var sTitle = p_sTitle;
890 if (this.get("type") != "link") {
894 switch (this.get("type")) {
898 sTitle = this.RADIO_DEFAULT_TITLE;
904 sTitle = this.CHECKBOX_DEFAULT_TITLE;
910 sTitle = this.MENUBUTTON_DEFAULT_TITLE;
916 sTitle = this.SPLITBUTTON_DEFAULT_TITLE;
922 sTitle = this.SUBMIT_TITLE;
930 this._button.title = sTitle;
938 * @method _setDisabled
939 * @description Sets the value of the button's "disabled" attribute.
941 * @param {Boolean} p_bDisabled Boolean indicating the value for
942 * the button's "disabled" attribute.
944 _setDisabled: function (p_bDisabled) {
946 if (this.get("type") != "link") {
956 if (this.hasFocus()) {
962 this._button.setAttribute("disabled", "disabled");
964 this.addStateCSSClasses("disabled");
966 this.removeStateCSSClasses("hover");
967 this.removeStateCSSClasses("active");
968 this.removeStateCSSClasses("focus");
973 this._button.removeAttribute("disabled");
975 this.removeStateCSSClasses("disabled");
986 * @description Sets the value of the button's "href" attribute.
988 * @param {String} p_sHref String indicating the value for the button's
991 _setHref: function (p_sHref) {
993 if (this.get("type") == "link") {
995 this._button.href = p_sHref;
1003 * @method _setTarget
1004 * @description Sets the value of the button's "target" attribute.
1006 * @param {String} p_sTarget String indicating the value for the button's
1007 * "target" attribute.
1009 _setTarget: function (p_sTarget) {
1011 if (this.get("type") == "link") {
1013 this._button.setAttribute("target", p_sTarget);
1021 * @method _setChecked
1022 * @description Sets the value of the button's "target" attribute.
1024 * @param {Boolean} p_bChecked Boolean indicating the value for
1025 * the button's "checked" attribute.
1027 _setChecked: function (p_bChecked) {
1029 var sType = this.get("type"),
1032 if (sType == "checkbox" || sType == "radio") {
1036 this.addStateCSSClasses("checked");
1038 sTitle = (sType == "radio") ?
1039 this.RADIO_CHECKED_TITLE :
1040 this.CHECKBOX_CHECKED_TITLE;
1045 this.removeStateCSSClasses("checked");
1047 sTitle = (sType == "radio") ?
1048 this.RADIO_DEFAULT_TITLE :
1049 this.CHECKBOX_DEFAULT_TITLE;
1054 if (!this._hasDefaultTitle) {
1056 this.set("title", sTitle);
1067 * @description Sets the value of the button's "menu" attribute.
1069 * @param {Object} p_oMenu Object indicating the value for the button's
1072 _setMenu: function (p_oMenu) {
1074 var bLazyLoad = this.get("lazyloadmenu"),
1075 oButtonElement = this.get("element"),
1079 Boolean indicating if the value of p_oMenu is an instance
1080 of YAHOO.widget.Menu or YAHOO.widget.Overlay.
1089 function onAppendTo() {
1091 oMenu.render(oButtonElement.parentNode);
1093 this.removeListener("appendTo", onAppendTo);
1098 function setMenuContainer() {
1100 oMenu.cfg.queueProperty("container", oButtonElement.parentNode);
1102 this.removeListener("appendTo", setMenuContainer);
1107 function initMenu() {
1113 Dom.addClass(oMenu.element, this.get("menuclassname"));
1114 Dom.addClass(oMenu.element, "yui-" + this.get("type") + "-button-menu");
1116 oMenu.showEvent.subscribe(this._onMenuShow, null, this);
1117 oMenu.hideEvent.subscribe(this._onMenuHide, null, this);
1118 oMenu.renderEvent.subscribe(this._onMenuRender, null, this);
1121 if (Menu && oMenu instanceof Menu) {
1125 oContainer = this.get("container");
1129 oMenu.cfg.queueProperty("container", oContainer);
1134 this.on("appendTo", setMenuContainer);
1140 oMenu.cfg.queueProperty("clicktohide", false);
1142 oMenu.keyDownEvent.subscribe(this._onMenuKeyDown, this, true);
1143 oMenu.subscribe("click", this._onMenuClick, this, true);
1145 this.on("selectedMenuItemChange", this._onSelectedMenuItemChange);
1147 oSrcElement = oMenu.srcElement;
1149 if (oSrcElement && oSrcElement.nodeName.toUpperCase() == "SELECT") {
1151 oSrcElement.style.display = "none";
1152 oSrcElement.parentNode.removeChild(oSrcElement);
1157 else if (Overlay && oMenu instanceof Overlay) {
1159 if (!m_oOverlayManager) {
1161 m_oOverlayManager = new YAHOO.widget.OverlayManager();
1165 m_oOverlayManager.register(oMenu);
1173 if (!bInstance && !bLazyLoad) {
1175 if (Dom.inDocument(oButtonElement)) {
1177 oMenu.render(oButtonElement.parentNode);
1182 this.on("appendTo", onAppendTo);
1197 sMenuCSSClassName = Menu.prototype.CSS_CLASS_NAME;
1201 if (p_oMenu && Menu && (p_oMenu instanceof Menu)) {
1206 initMenu.call(this);
1209 else if (Overlay && p_oMenu && (p_oMenu instanceof Overlay)) {
1214 oMenu.cfg.queueProperty("visible", false);
1216 initMenu.call(this);
1219 else if (Menu && Lang.isArray(p_oMenu)) {
1221 oMenu = new Menu(Dom.generateId(), { lazyload: bLazyLoad, itemdata: p_oMenu });
1225 this.on("appendTo", initMenu);
1228 else if (Lang.isString(p_oMenu)) {
1230 oMenuElement = Dom.get(p_oMenu);
1234 if (Menu && Dom.hasClass(oMenuElement, sMenuCSSClassName) ||
1235 oMenuElement.nodeName.toUpperCase() == "SELECT") {
1237 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1239 initMenu.call(this);
1244 oMenu = new Overlay(p_oMenu, { visible: false });
1246 initMenu.call(this);
1253 else if (p_oMenu && p_oMenu.nodeName) {
1255 if (Menu && Dom.hasClass(p_oMenu, sMenuCSSClassName) ||
1256 p_oMenu.nodeName.toUpperCase() == "SELECT") {
1258 oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
1260 initMenu.call(this);
1267 Dom.generateId(p_oMenu);
1271 oMenu = new Overlay(p_oMenu, { visible: false });
1273 initMenu.call(this);
1285 * @method _setOnClick
1286 * @description Sets the value of the button's "onclick" attribute.
1288 * @param {Object} p_oObject Object indicating the value for the button's
1289 * "onclick" attribute.
1291 _setOnClick: function (p_oObject) {
1294 Remove any existing listeners if a "click" event handler
1295 has already been specified.
1298 if (this._onclickAttributeValue &&
1299 (this._onclickAttributeValue != p_oObject)) {
1301 this.removeListener("click", this._onclickAttributeValue.fn);
1303 this._onclickAttributeValue = null;
1308 if (!this._onclickAttributeValue &&
1309 Lang.isObject(p_oObject) &&
1310 Lang.isFunction(p_oObject.fn)) {
1312 this.on("click", p_oObject.fn, p_oObject.obj, p_oObject.scope);
1314 this._onclickAttributeValue = p_oObject;
1322 // Protected methods
1327 * @method _isActivationKey
1328 * @description Determines if the specified keycode is one that toggles
1329 * the button's "active" state.
1331 * @param {Number} p_nKeyCode Number representing the keycode to
1335 _isActivationKey: function (p_nKeyCode) {
1337 var sType = this.get("type"),
1338 aKeyCodes = (sType == "checkbox" || sType == "radio") ?
1339 this.CHECK_ACTIVATION_KEYS : this.ACTIVATION_KEYS,
1341 nKeyCodes = aKeyCodes.length,
1346 if (nKeyCodes > 0) {
1352 if (p_nKeyCode == aKeyCodes[i]) {
1370 * @method _isSplitButtonOptionKey
1371 * @description Determines if the specified keycode is one that toggles
1372 * the display of the split button's menu.
1374 * @param {Event} p_oEvent Object representing the DOM event object
1375 * passed back by the event utility (YAHOO.util.Event).
1378 _isSplitButtonOptionKey: function (p_oEvent) {
1380 var bShowMenu = (Event.getCharCode(p_oEvent) == 40);
1383 var onKeyPress = function (p_oEvent) {
1385 Event.preventDefault(p_oEvent);
1387 this.removeListener("keypress", onKeyPress);
1392 // Prevent the browser from scrolling the window
1397 this.on("keypress", onKeyPress);
1401 Event.preventDefault(p_oEvent);
1410 * @method _addListenersToForm
1411 * @description Adds event handlers to the button's form.
1414 _addListenersToForm: function () {
1416 var oForm = this.getForm(),
1417 onFormKeyPress = YAHOO.widget.Button.onFormKeyPress,
1418 bHasKeyPressListener,
1427 Event.on(oForm, "reset", this._onFormReset, null, this);
1428 Event.on(oForm, "submit", this._onFormSubmit, null, this);
1430 oSrcElement = this.get("srcelement");
1433 if (this.get("type") == "submit" ||
1434 (oSrcElement && oSrcElement.type == "submit"))
1437 aListeners = Event.getListeners(oForm, "keypress");
1438 bHasKeyPressListener = false;
1442 nListeners = aListeners.length;
1444 if (nListeners > 0) {
1450 if (aListeners[i].fn == onFormKeyPress) {
1452 bHasKeyPressListener = true;
1465 if (!bHasKeyPressListener) {
1467 Event.on(oForm, "keypress", onFormKeyPress);
1481 * @description Shows the button's menu.
1483 * @param {Event} p_oEvent Object representing the DOM event object
1484 * passed back by the event utility (YAHOO.util.Event) that triggered
1485 * the display of the menu.
1487 _showMenu: function (p_oEvent) {
1489 if (YAHOO.widget.MenuManager) {
1490 YAHOO.widget.MenuManager.hideVisible();
1494 if (m_oOverlayManager) {
1495 m_oOverlayManager.hideAll();
1499 var oMenu = this._menu,
1500 aMenuAlignment = this.get("menualignment"),
1501 bFocusMenu = this.get("focusmenu"),
1505 if (this._renderedMenu) {
1507 oMenu.cfg.setProperty("context",
1508 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1510 oMenu.cfg.setProperty("preventcontextoverlap", true);
1511 oMenu.cfg.setProperty("constraintoviewport", true);
1516 oMenu.cfg.queueProperty("context",
1517 [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]);
1519 oMenu.cfg.queueProperty("preventcontextoverlap", true);
1520 oMenu.cfg.queueProperty("constraintoviewport", true);
1526 Refocus the Button before showing its Menu in case the call to
1527 YAHOO.widget.MenuManager.hideVisible() resulted in another element in the
1528 DOM being focused after another Menu was hidden.
1534 if (Menu && oMenu && (oMenu instanceof Menu)) {
1536 // Since Menus automatically focus themselves when made visible, temporarily
1537 // replace the Menu focus method so that the value of the Button's "focusmenu"
1538 // attribute determines if the Menu should be focus when made visible.
1540 fnFocusMethod = oMenu.focus;
1542 oMenu.focus = function () {};
1544 if (this._renderedMenu) {
1546 oMenu.cfg.setProperty("minscrollheight", this.get("menuminscrollheight"));
1547 oMenu.cfg.setProperty("maxheight", this.get("menumaxheight"));
1552 oMenu.cfg.queueProperty("minscrollheight", this.get("menuminscrollheight"));
1553 oMenu.cfg.queueProperty("maxheight", this.get("menumaxheight"));
1560 oMenu.focus = fnFocusMethod;
1566 Stop the propagation of the event so that the MenuManager
1567 doesn't blur the menu after it gets focus.
1570 if (p_oEvent.type == "mousedown") {
1571 Event.stopPropagation(p_oEvent);
1580 else if (Overlay && oMenu && (oMenu instanceof Overlay)) {
1582 if (!this._renderedMenu) {
1583 oMenu.render(this.get("element").parentNode);
1596 * @description Hides the button's menu.
1599 _hideMenu: function () {
1601 var oMenu = this._menu;
1614 // Protected event handlers
1618 * @method _onMouseOver
1619 * @description "mouseover" event handler for the button.
1621 * @param {Event} p_oEvent Object representing the DOM event object
1622 * passed back by the event utility (YAHOO.util.Event).
1624 _onMouseOver: function (p_oEvent) {
1626 var sType = this.get("type"),
1631 if (sType === "split") {
1633 oElement = this.get("element");
1635 (Dom.getX(oElement) + (oElement.offsetWidth - this.OPTION_AREA_WIDTH));
1637 this._nOptionRegionX = nOptionRegionX;
1642 if (!this._hasMouseEventHandlers) {
1644 if (sType === "split") {
1646 this.on("mousemove", this._onMouseMove);
1650 this.on("mouseout", this._onMouseOut);
1652 this._hasMouseEventHandlers = true;
1657 this.addStateCSSClasses("hover");
1660 if (sType === "split" && (Event.getPageX(p_oEvent) > nOptionRegionX)) {
1662 this.addStateCSSClasses("hoveroption");
1667 if (this._activationButtonPressed) {
1669 this.addStateCSSClasses("active");
1674 if (this._bOptionPressed) {
1676 this.addStateCSSClasses("activeoption");
1681 if (this._activationButtonPressed || this._bOptionPressed) {
1683 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1691 * @method _onMouseMove
1692 * @description "mousemove" event handler for the button.
1694 * @param {Event} p_oEvent Object representing the DOM event object
1695 * passed back by the event utility (YAHOO.util.Event).
1697 _onMouseMove: function (p_oEvent) {
1699 var nOptionRegionX = this._nOptionRegionX;
1701 if (nOptionRegionX) {
1703 if (Event.getPageX(p_oEvent) > nOptionRegionX) {
1705 this.addStateCSSClasses("hoveroption");
1710 this.removeStateCSSClasses("hoveroption");
1719 * @method _onMouseOut
1720 * @description "mouseout" event handler for the button.
1722 * @param {Event} p_oEvent Object representing the DOM event object
1723 * passed back by the event utility (YAHOO.util.Event).
1725 _onMouseOut: function (p_oEvent) {
1727 var sType = this.get("type");
1729 this.removeStateCSSClasses("hover");
1732 if (sType != "menu") {
1734 this.removeStateCSSClasses("active");
1739 if (this._activationButtonPressed || this._bOptionPressed) {
1741 Event.on(document, "mouseup", this._onDocumentMouseUp, null, this);
1746 if (sType === "split" && (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
1748 this.removeStateCSSClasses("hoveroption");
1756 * @method _onDocumentMouseUp
1757 * @description "mouseup" event handler for the button.
1759 * @param {Event} p_oEvent Object representing the DOM event object
1760 * passed back by the event utility (YAHOO.util.Event).
1762 _onDocumentMouseUp: function (p_oEvent) {
1764 this._activationButtonPressed = false;
1765 this._bOptionPressed = false;
1767 var sType = this.get("type"),
1771 if (sType == "menu" || sType == "split") {
1773 oTarget = Event.getTarget(p_oEvent);
1774 oMenuElement = this._menu.element;
1776 if (oTarget != oMenuElement &&
1777 !Dom.isAncestor(oMenuElement, oTarget)) {
1779 this.removeStateCSSClasses((sType == "menu" ?
1780 "active" : "activeoption"));
1788 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
1794 * @method _onMouseDown
1795 * @description "mousedown" event handler for the button.
1797 * @param {Event} p_oEvent Object representing the DOM event object
1798 * passed back by the event utility (YAHOO.util.Event).
1800 _onMouseDown: function (p_oEvent) {
1806 function onMouseUp() {
1809 this.removeListener("mouseup", onMouseUp);
1814 if ((p_oEvent.which || p_oEvent.button) == 1) {
1817 if (!this.hasFocus()) {
1824 sType = this.get("type");
1827 if (sType == "split") {
1829 if (Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1831 this.fireEvent("option", p_oEvent);
1837 this.addStateCSSClasses("active");
1839 this._activationButtonPressed = true;
1844 else if (sType == "menu") {
1846 if (this.isActive()) {
1850 this._activationButtonPressed = false;
1855 this._showMenu(p_oEvent);
1857 this._activationButtonPressed = true;
1864 this.addStateCSSClasses("active");
1866 this._activationButtonPressed = true;
1872 if (sType == "split" || sType == "menu") {
1874 this._hideMenuTimer = Lang.later(250, this, this.on, ["mouseup", onMouseUp]);
1886 * @method _onMouseUp
1887 * @description "mouseup" event handler for the button.
1889 * @param {Event} p_oEvent Object representing the DOM event object
1890 * passed back by the event utility (YAHOO.util.Event).
1892 _onMouseUp: function (p_oEvent) {
1894 var sType = this.get("type"),
1895 oHideMenuTimer = this._hideMenuTimer,
1899 if (oHideMenuTimer) {
1901 oHideMenuTimer.cancel();
1906 if (sType == "checkbox" || sType == "radio") {
1908 this.set("checked", !(this.get("checked")));
1913 this._activationButtonPressed = false;
1916 if (sType != "menu") {
1918 this.removeStateCSSClasses("active");
1923 if (sType == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
1936 * @description "focus" event handler for the button.
1938 * @param {Event} p_oEvent Object representing the DOM event object
1939 * passed back by the event utility (YAHOO.util.Event).
1941 _onFocus: function (p_oEvent) {
1945 this.addStateCSSClasses("focus");
1947 if (this._activationKeyPressed) {
1949 this.addStateCSSClasses("active");
1953 m_oFocusedButton = this;
1956 if (!this._hasKeyEventHandlers) {
1958 oElement = this._button;
1960 Event.on(oElement, "blur", this._onBlur, null, this);
1961 Event.on(oElement, "keydown", this._onKeyDown, null, this);
1962 Event.on(oElement, "keyup", this._onKeyUp, null, this);
1964 this._hasKeyEventHandlers = true;
1969 this.fireEvent("focus", p_oEvent);
1976 * @description "blur" event handler for the button.
1978 * @param {Event} p_oEvent Object representing the DOM event object
1979 * passed back by the event utility (YAHOO.util.Event).
1981 _onBlur: function (p_oEvent) {
1983 this.removeStateCSSClasses("focus");
1985 if (this.get("type") != "menu") {
1987 this.removeStateCSSClasses("active");
1991 if (this._activationKeyPressed) {
1993 Event.on(document, "keyup", this._onDocumentKeyUp, null, this);
1998 m_oFocusedButton = null;
2000 this.fireEvent("blur", p_oEvent);
2006 * @method _onDocumentKeyUp
2007 * @description "keyup" event handler for the document.
2009 * @param {Event} p_oEvent Object representing the DOM event object
2010 * passed back by the event utility (YAHOO.util.Event).
2012 _onDocumentKeyUp: function (p_oEvent) {
2014 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
2016 this._activationKeyPressed = false;
2018 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
2026 * @method _onKeyDown
2027 * @description "keydown" event handler for the button.
2029 * @param {Event} p_oEvent Object representing the DOM event object
2030 * passed back by the event utility (YAHOO.util.Event).
2032 _onKeyDown: function (p_oEvent) {
2034 var oMenu = this._menu;
2037 if (this.get("type") == "split" &&
2038 this._isSplitButtonOptionKey(p_oEvent)) {
2040 this.fireEvent("option", p_oEvent);
2043 else if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
2045 if (this.get("type") == "menu") {
2047 this._showMenu(p_oEvent);
2052 this._activationKeyPressed = true;
2054 this.addStateCSSClasses("active");
2061 if (oMenu && oMenu.cfg.getProperty("visible") &&
2062 Event.getCharCode(p_oEvent) == 27) {
2074 * @description "keyup" event handler for the button.
2076 * @param {Event} p_oEvent Object representing the DOM event object
2077 * passed back by the event utility (YAHOO.util.Event).
2079 _onKeyUp: function (p_oEvent) {
2083 if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
2085 sType = this.get("type");
2087 if (sType == "checkbox" || sType == "radio") {
2089 this.set("checked", !(this.get("checked")));
2093 this._activationKeyPressed = false;
2095 if (this.get("type") != "menu") {
2097 this.removeStateCSSClasses("active");
2108 * @description "click" event handler for the button.
2110 * @param {Event} p_oEvent Object representing the DOM event object
2111 * passed back by the event utility (YAHOO.util.Event).
2113 _onClick: function (p_oEvent) {
2115 var sType = this.get("type"),
2127 if (!this._hasDefaultTitle) {
2129 if (this.get("checked")) {
2131 sTitle = (sType == "radio") ?
2132 this.RADIO_CHECKED_TITLE :
2133 this.CHECKBOX_CHECKED_TITLE;
2138 sTitle = (sType == "radio") ?
2139 this.RADIO_DEFAULT_TITLE :
2140 this.CHECKBOX_DEFAULT_TITLE;
2144 this.set("title", sTitle);
2152 if (p_oEvent.returnValue !== false) {
2162 oForm = this.getForm();
2174 sTitle = this._menu.cfg.getProperty("visible") ?
2175 this.MENUBUTTON_MENU_VISIBLE_TITLE :
2176 this.MENUBUTTON_DEFAULT_TITLE;
2178 this.set("title", sTitle);
2184 if (this._nOptionRegionX > 0 &&
2185 (Event.getPageX(p_oEvent) > this._nOptionRegionX)) {
2194 oSrcElement = this.get("srcelement");
2196 if (oSrcElement && oSrcElement.type == "submit" &&
2197 p_oEvent.returnValue !== false) {
2205 sTitle = this._menu.cfg.getProperty("visible") ?
2206 this.SPLITBUTTON_OPTION_VISIBLE_TITLE :
2207 this.SPLITBUTTON_DEFAULT_TITLE;
2209 this.set("title", sTitle);
2221 * @method _onDblClick
2222 * @description "dblclick" event handler for the button.
2224 * @param {Event} p_oEvent Object representing the DOM event object
2225 * passed back by the event utility (YAHOO.util.Event).
2227 _onDblClick: function (p_oEvent) {
2229 var bReturnVal = true;
2231 if (this.get("type") == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) {
2243 * @method _onAppendTo
2244 * @description "appendTo" event handler for the button.
2246 * @param {Event} p_oEvent Object representing the DOM event object
2247 * passed back by the event utility (YAHOO.util.Event).
2249 _onAppendTo: function (p_oEvent) {
2252 It is necessary to call "_addListenersToForm" using
2253 "setTimeout" to make sure that the button's "form" property
2254 returns a node reference. Sometimes, if you try to get the
2255 reference immediately after appending the field, it is null.
2258 Lang.later(0, this, this._addListenersToForm);
2264 * @method _onFormReset
2265 * @description "reset" event handler for the button's form.
2267 * @param {Event} p_oEvent Object representing the DOM event
2268 * object passed back by the event utility (YAHOO.util.Event).
2270 _onFormReset: function (p_oEvent) {
2272 var sType = this.get("type"),
2275 if (sType == "checkbox" || sType == "radio") {
2277 this.resetValue("checked");
2282 if (Menu && oMenu && (oMenu instanceof Menu)) {
2284 this.resetValue("selectedMenuItem");
2292 * @method _onFormSubmit
2293 * @description "submit" event handler for the button's form.
2295 * @param {Event} p_oEvent Object representing the DOM event
2296 * object passed back by the event utility (YAHOO.util.Event).
2298 _onFormSubmit: function (p_oEvent) {
2300 this.createHiddenFields();
2306 * @method _onDocumentMouseDown
2307 * @description "mousedown" event handler for the document.
2309 * @param {Event} p_oEvent Object representing the DOM event object
2310 * passed back by the event utility (YAHOO.util.Event).
2312 _onDocumentMouseDown: function (p_oEvent) {
2314 var oTarget = Event.getTarget(p_oEvent),
2315 oButtonElement = this.get("element"),
2316 oMenuElement = this._menu.element;
2319 if (oTarget != oButtonElement &&
2320 !Dom.isAncestor(oButtonElement, oTarget) &&
2321 oTarget != oMenuElement &&
2322 !Dom.isAncestor(oMenuElement, oTarget)) {
2326 Event.removeListener(document, "mousedown",
2327 this._onDocumentMouseDown);
2336 * @description "option" event handler for the button.
2338 * @param {Event} p_oEvent Object representing the DOM event object
2339 * passed back by the event utility (YAHOO.util.Event).
2341 _onOption: function (p_oEvent) {
2343 if (this.hasClass("yui-split-button-activeoption")) {
2347 this._bOptionPressed = false;
2352 this._showMenu(p_oEvent);
2354 this._bOptionPressed = true;
2362 * @method _onMenuShow
2363 * @description "show" event handler for the button's menu.
2365 * @param {String} p_sType String representing the name of the event
2368 _onMenuShow: function (p_sType) {
2370 Event.on(document, "mousedown", this._onDocumentMouseDown,
2376 if (this.get("type") == "split") {
2378 sTitle = this.SPLITBUTTON_OPTION_VISIBLE_TITLE;
2379 sState = "activeoption";
2384 sTitle = this.MENUBUTTON_MENU_VISIBLE_TITLE;
2389 this.addStateCSSClasses(sState);
2390 this.set("title", sTitle);
2396 * @method _onMenuHide
2397 * @description "hide" event handler for the button's menu.
2399 * @param {String} p_sType String representing the name of the event
2402 _onMenuHide: function (p_sType) {
2404 var oMenu = this._menu,
2409 if (this.get("type") == "split") {
2411 sTitle = this.SPLITBUTTON_DEFAULT_TITLE;
2412 sState = "activeoption";
2417 sTitle = this.MENUBUTTON_DEFAULT_TITLE;
2422 this.removeStateCSSClasses(sState);
2423 this.set("title", sTitle);
2426 if (this.get("type") == "split") {
2428 this._bOptionPressed = false;
2436 * @method _onMenuKeyDown
2437 * @description "keydown" event handler for the button's menu.
2439 * @param {String} p_sType String representing the name of the event
2441 * @param {Array} p_aArgs Array of arguments sent when the event
2444 _onMenuKeyDown: function (p_sType, p_aArgs) {
2446 var oEvent = p_aArgs[0];
2448 if (Event.getCharCode(oEvent) == 27) {
2452 if (this.get("type") == "split") {
2454 this._bOptionPressed = false;
2464 * @method _onMenuRender
2465 * @description "render" event handler for the button's menu.
2467 * @param {String} p_sType String representing the name of the
2468 * event thatwas fired.
2470 _onMenuRender: function (p_sType) {
2472 var oButtonElement = this.get("element"),
2473 oButtonParent = oButtonElement.parentNode,
2475 oMenuElement = oMenu.element,
2476 oSrcElement = oMenu.srcElement;
2479 if (oButtonParent != oMenuElement.parentNode) {
2481 oButtonParent.appendChild(oMenuElement);
2485 this._renderedMenu = true;
2487 // If the user has designated an <option> of the Menu's source
2488 // <select> element to be selected, sync the selectedIndex with
2489 // the "selectedMenuItem" Attribute.
2492 oSrcElement.nodeName.toLowerCase() === "select" &&
2493 oSrcElement.value) {
2495 this.set("selectedMenuItem",
2496 oMenu.getItem(oSrcElement.selectedIndex));
2505 * @method _onMenuClick
2506 * @description "click" event handler for the button's menu.
2508 * @param {String} p_sType String representing the name of the event
2510 * @param {Array} p_aArgs Array of arguments sent when the event
2513 _onMenuClick: function (p_sType, p_aArgs) {
2515 var oItem = p_aArgs[1],
2520 this.set("selectedMenuItem", oItem);
2522 oSrcElement = this.get("srcelement");
2524 if (oSrcElement && oSrcElement.type == "submit") {
2538 * @method _onSelectedMenuItemChange
2539 * @description "selectedMenuItemChange" event handler for the Button's
2540 * "selectedMenuItem" attribute.
2541 * @param {Event} event Object representing the DOM event object
2542 * passed back by the event utility (YAHOO.util.Event).
2544 _onSelectedMenuItemChange: function (event) {
2546 var oSelected = event.prevValue,
2547 oItem = event.newValue;
2550 Dom.removeClass(oSelected.element, "yui-button-selectedmenuitem");
2554 Dom.addClass(oItem.element, "yui-button-selectedmenuitem");
2564 * @method createButtonElement
2565 * @description Creates the button's HTML elements.
2566 * @param {String} p_sType String indicating the type of element
2568 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2569 * level-one-html.html#ID-58190037">HTMLElement</a>}
2571 createButtonElement: function (p_sType) {
2573 var sNodeName = this.NODE_NAME,
2574 oElement = document.createElement(sNodeName);
2576 oElement.innerHTML = "<" + sNodeName + " class=\"first-child\">" +
2577 (p_sType == "link" ? "<a></a>" :
2578 "<button type=\"button\"></button>") + "</" + sNodeName + ">";
2586 * @method addStateCSSClasses
2587 * @description Appends state-specific CSS classes to the button's root
2590 addStateCSSClasses: function (p_sState) {
2592 var sType = this.get("type");
2594 if (Lang.isString(p_sState)) {
2596 if (p_sState != "activeoption" && p_sState != "hoveroption") {
2598 this.addClass(this.CSS_CLASS_NAME + ("-" + p_sState));
2602 this.addClass("yui-" + sType + ("-button-" + p_sState));
2610 * @method removeStateCSSClasses
2611 * @description Removes state-specific CSS classes to the button's root
2614 removeStateCSSClasses: function (p_sState) {
2616 var sType = this.get("type");
2618 if (Lang.isString(p_sState)) {
2620 this.removeClass(this.CSS_CLASS_NAME + ("-" + p_sState));
2621 this.removeClass("yui-" + sType + ("-button-" + p_sState));
2629 * @method createHiddenFields
2630 * @description Creates the button's hidden form field and appends it
2631 * to its parent form.
2632 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2633 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
2635 createHiddenFields: function () {
2637 this.removeHiddenFields();
2639 var oForm = this.getForm(),
2651 bMenuSrcElementIsSelect = false;
2654 if (oForm && !this.get("disabled")) {
2656 sType = this.get("type");
2657 bCheckable = (sType == "checkbox" || sType == "radio");
2660 if ((bCheckable && this.get("checked")) || (m_oSubmitTrigger == this)) {
2662 YAHOO.log("Creating hidden field.", "info", this.toString());
2664 oButtonField = createInputElement((bCheckable ? sType : "hidden"),
2665 this.get("name"), this.get("value"), this.get("checked"));
2672 oButtonField.style.display = "none";
2676 oForm.appendChild(oButtonField);
2686 if (Menu && oMenu && (oMenu instanceof Menu)) {
2688 YAHOO.log("Creating hidden field for menu.", "info", this.toString());
2690 oMenuItem = this.get("selectedMenuItem");
2691 oMenuSrcElement = oMenu.srcElement;
2692 bMenuSrcElementIsSelect = (oMenuSrcElement &&
2693 oMenuSrcElement.nodeName.toUpperCase() == "SELECT");
2697 oValue = (oMenuItem.value === null || oMenuItem.value === "") ?
2698 oMenuItem.cfg.getProperty("text") : oMenuItem.value;
2700 sButtonName = this.get("name");
2703 if (bMenuSrcElementIsSelect) {
2705 sMenuFieldName = oMenuSrcElement.name;
2708 else if (sButtonName) {
2710 sMenuFieldName = (sButtonName + "_options");
2715 if (oValue && sMenuFieldName) {
2717 oMenuField = createInputElement("hidden", sMenuFieldName, oValue);
2718 oForm.appendChild(oMenuField);
2723 else if (bMenuSrcElementIsSelect) {
2725 oForm.appendChild(oMenuSrcElement);
2732 if (oButtonField && oMenuField) {
2734 this._hiddenFields = [oButtonField, oMenuField];
2737 else if (!oButtonField && oMenuField) {
2739 this._hiddenFields = oMenuField;
2742 else if (oButtonField && !oMenuField) {
2744 this._hiddenFields = oButtonField;
2748 oReturnVal = this._hiddenFields;
2758 * @method removeHiddenFields
2759 * @description Removes the button's hidden form field(s) from its
2762 removeHiddenFields: function () {
2764 var oField = this._hiddenFields,
2768 function removeChild(p_oElement) {
2770 if (Dom.inDocument(p_oElement)) {
2772 p_oElement.parentNode.removeChild(p_oElement);
2781 if (Lang.isArray(oField)) {
2783 nFields = oField.length;
2791 removeChild(oField[i]);
2801 removeChild(oField);
2805 this._hiddenFields = null;
2813 * @method submitForm
2814 * @description Submits the form to which the button belongs. Returns
2815 * true if the form was submitted successfully, false if the submission
2820 submitForm: function () {
2822 var oForm = this.getForm(),
2824 oSrcElement = this.get("srcelement"),
2827 Boolean indicating if the event fired successfully
2828 (was not cancelled by any handlers)
2831 bSubmitForm = false,
2838 if (this.get("type") == "submit" || (oSrcElement && oSrcElement.type == "submit")) {
2840 m_oSubmitTrigger = this;
2847 bSubmitForm = oForm.fireEvent("onsubmit");
2850 else { // Gecko, Opera, and Safari
2852 oEvent = document.createEvent("HTMLEvents");
2853 oEvent.initEvent("submit", true, true);
2855 bSubmitForm = oForm.dispatchEvent(oEvent);
2861 In IE and Safari, dispatching a "submit" event to a form
2862 WILL cause the form's "submit" event to fire, but WILL NOT
2863 submit the form. Therefore, we need to call the "submit"
2867 if ((UA.ie || UA.webkit) && bSubmitForm) {
2882 * @description The Button class's initialization method.
2883 * @param {String} p_oElement String specifying the id attribute of the
2884 * <code><input></code>, <code><button></code>,
2885 * <code><a></code>, or <code><span></code> element to
2886 * be used to create the button.
2887 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
2888 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://
2889 * www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
2890 * #ID-34812697">HTMLButtonElement</a>|<a href="http://www.w3.org/TR
2891 * /2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-33759296">
2892 * HTMLElement</a>} p_oElement Object reference for the
2893 * <code><input></code>, <code><button></code>,
2894 * <code><a></code>, or <code><span></code> element to be
2895 * used to create the button.
2896 * @param {Object} p_oElement Object literal specifying a set of
2897 * configuration attributes used to create the button.
2898 * @param {Object} p_oAttributes Optional. Object literal specifying a
2899 * set of configuration attributes used to create the button.
2901 init: function (p_oElement, p_oAttributes) {
2903 var sNodeName = p_oAttributes.type == "link" ? "a" : "button",
2904 oSrcElement = p_oAttributes.srcelement,
2905 oButton = p_oElement.getElementsByTagName(sNodeName)[0],
2911 oInput = p_oElement.getElementsByTagName("input")[0];
2916 oButton = document.createElement("button");
2917 oButton.setAttribute("type", "button");
2919 oInput.parentNode.replaceChild(oButton, oInput);
2925 this._button = oButton;
2928 Capture if the button has a value for the title attribute. If so, we won't
2929 override it for type of "checkbox" or "radio".
2932 this._hasDefaultTitle = (p_oAttributes.title && p_oAttributes.title.length > 0);
2934 YAHOO.widget.Button.superclass.init.call(this, p_oElement, p_oAttributes);
2937 var sId = this.get("id"),
2938 sButtonId = sId + "-button";
2941 oButton.id = sButtonId;
2948 var hasLabel = function (element) {
2950 return (element.htmlFor === sId);
2955 var setLabel = function () {
2957 oLabel.setAttribute((UA.ie ? "htmlFor" : "for"), sButtonId);
2962 if (oSrcElement && this.get("type") != "link") {
2964 aLabels = Dom.getElementsBy(hasLabel, "label");
2966 if (Lang.isArray(aLabels) && aLabels.length > 0) {
2968 oLabel = aLabels[0];
2975 m_oButtons[sId] = this;
2978 this.addClass(this.CSS_CLASS_NAME);
2979 this.addClass("yui-" + this.get("type") + "-button");
2981 Event.on(this._button, "focus", this._onFocus, null, this);
2982 this.on("mouseover", this._onMouseOver);
2983 this.on("mousedown", this._onMouseDown);
2984 this.on("mouseup", this._onMouseUp);
2985 this.on("click", this._onClick);
2987 // Need to reset the value of the "onclick" Attribute so that any
2988 // handlers registered via the "onclick" Attribute are fired after
2989 // Button's default "_onClick" listener.
2991 var fnOnClick = this.get("onclick");
2993 this.set("onclick", null);
2994 this.set("onclick", fnOnClick);
2996 this.on("dblclick", this._onDblClick);
3000 this.on("appendTo", setLabel);
3004 this.on("appendTo", this._onAppendTo);
3008 var oContainer = this.get("container"),
3009 oElement = this.get("element"),
3010 bElInDoc = Dom.inDocument(oElement),
3016 if (oSrcElement && oSrcElement != oElement) {
3018 oParentNode = oSrcElement.parentNode;
3022 oParentNode.removeChild(oSrcElement);
3028 if (Lang.isString(oContainer)) {
3030 Event.onContentReady(oContainer, this.appendTo, oContainer, this);
3035 this.on("init", function () {
3037 Lang.later(0, this, this.appendTo, oContainer);
3044 else if (!bElInDoc && oSrcElement && oSrcElement != oElement) {
3046 oParentNode = oSrcElement.parentNode;
3050 this.fireEvent("beforeAppendTo", {
3051 type: "beforeAppendTo",
3055 oParentNode.replaceChild(oElement, oSrcElement);
3057 this.fireEvent("appendTo", {
3065 else if (this.get("type") != "link" && bElInDoc && oSrcElement &&
3066 oSrcElement == oElement) {
3068 this._addListenersToForm();
3072 YAHOO.log("Initialization completed.", "info", this.toString());
3075 this.fireEvent("init", {
3084 * @method initAttributes
3085 * @description Initializes all of the configuration attributes used to
3086 * create the button.
3087 * @param {Object} p_oAttributes Object literal specifying a set of
3088 * configuration attributes used to create the button.
3090 initAttributes: function (p_oAttributes) {
3092 var oAttributes = p_oAttributes || {};
3094 YAHOO.widget.Button.superclass.initAttributes.call(this,
3100 * @description String specifying the button's type. Possible
3101 * values are: "push," "link," "submit," "reset," "checkbox,"
3102 * "radio," "menu," and "split."
3107 this.setAttributeConfig("type", {
3109 value: (oAttributes.type || "push"),
3110 validator: Lang.isString,
3112 method: this._setType
3119 * @description String specifying the button's text label
3124 this.setAttributeConfig("label", {
3126 value: oAttributes.label,
3127 validator: Lang.isString,
3128 method: this._setLabel
3135 * @description Object specifying the value for the button.
3139 this.setAttributeConfig("value", {
3141 value: oAttributes.value
3148 * @description String specifying the name for the button.
3152 this.setAttributeConfig("name", {
3154 value: oAttributes.name,
3155 validator: Lang.isString
3161 * @attribute tabindex
3162 * @description Number specifying the tabindex for the button.
3166 this.setAttributeConfig("tabindex", {
3168 value: oAttributes.tabindex,
3169 validator: Lang.isNumber,
3170 method: this._setTabIndex
3177 * @description String specifying the title for the button.
3181 this.configureAttribute("title", {
3183 value: oAttributes.title,
3184 validator: Lang.isString,
3185 method: this._setTitle
3191 * @attribute disabled
3192 * @description Boolean indicating if the button should be disabled.
3193 * (Disabled buttons are dimmed and will not respond to user input
3194 * or fire events. Does not apply to button's of type "link.")
3198 this.setAttributeConfig("disabled", {
3200 value: (oAttributes.disabled || false),
3201 validator: Lang.isBoolean,
3202 method: this._setDisabled
3209 * @description String specifying the href for the button. Applies
3210 * only to buttons of type "link."
3213 this.setAttributeConfig("href", {
3215 value: oAttributes.href,
3216 validator: Lang.isString,
3217 method: this._setHref
3224 * @description String specifying the target for the button.
3225 * Applies only to buttons of type "link."
3228 this.setAttributeConfig("target", {
3230 value: oAttributes.target,
3231 validator: Lang.isString,
3232 method: this._setTarget
3238 * @attribute checked
3239 * @description Boolean indicating if the button is checked.
3240 * Applies only to buttons of type "radio" and "checkbox."
3244 this.setAttributeConfig("checked", {
3246 value: (oAttributes.checked || false),
3247 validator: Lang.isBoolean,
3248 method: this._setChecked
3254 * @attribute container
3255 * @description HTML element reference or string specifying the id
3256 * attribute of the HTML element that the button's markup should be
3258 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3259 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3263 this.setAttributeConfig("container", {
3265 value: oAttributes.container,
3272 * @attribute srcelement
3273 * @description Object reference to the HTML element (either
3274 * <code><input></code> or <code><span></code>)
3275 * used to create the button.
3276 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3277 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3281 this.setAttributeConfig("srcelement", {
3283 value: oAttributes.srcelement,
3291 * @description Object specifying the menu for the button.
3292 * The value can be one of the following:
3294 * <li>Object specifying a <a href="YAHOO.widget.Menu.html">
3295 * YAHOO.widget.Menu</a> instance.</li>
3296 * <li>Object specifying a <a href="YAHOO.widget.Overlay.html">
3297 * YAHOO.widget.Overlay</a> instance.</li>
3298 * <li>String specifying the id attribute of the <code><div>
3299 * </code> element used to create the menu. By default the menu
3300 * will be created as an instance of
3301 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>.
3302 * If the <a href="YAHOO.widget.Menu.html#CSS_CLASS_NAME">
3303 * default CSS class name for YAHOO.widget.Menu</a> is applied to
3304 * the <code><div></code> element, it will be created as an
3305 * instance of <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu
3306 * </a>.</li><li>String specifying the id attribute of the
3307 * <code><select></code> element used to create the menu.
3308 * </li><li>Object specifying the <code><div></code> element
3309 * used to create the menu.</li>
3310 * <li>Object specifying the <code><select></code> element
3311 * used to create the menu.</li>
3312 * <li>Array of object literals, each representing a set of
3313 * <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>
3314 * configuration attributes.</li>
3315 * <li>Array of strings representing the text labels for each menu
3316 * item in the menu.</li>
3318 * @type <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>|<a
3319 * href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|<a
3320 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3321 * one-html.html#ID-58190037">HTMLElement</a>|String|Array
3325 this.setAttributeConfig("menu", {
3328 method: this._setMenu,
3335 * @attribute lazyloadmenu
3336 * @description Boolean indicating the value to set for the
3337 * <a href="YAHOO.widget.Menu.html#lazyLoad">"lazyload"</a>
3338 * configuration property of the button's menu. Setting
3339 * "lazyloadmenu" to <code>true </code> will defer rendering of
3340 * the button's menu until the first time it is made visible.
3341 * If "lazyloadmenu" is set to <code>false</code>, the button's
3342 * menu will be rendered immediately if the button is in the
3343 * document, or in response to the button's "appendTo" event if
3344 * the button is not yet in the document. In either case, the
3345 * menu is rendered into the button's parent HTML element.
3346 * <em>This attribute does not apply if a
3347 * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a> or
3348 * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
3349 * instance is passed as the value of the button's "menu"
3350 * configuration attribute. <a href="YAHOO.widget.Menu.html">
3351 * YAHOO.widget.Menu</a> or <a href="YAHOO.widget.Overlay.html">
3352 * YAHOO.widget.Overlay</a> instances should be rendered before
3353 * being set as the value for the "menu" configuration
3359 this.setAttributeConfig("lazyloadmenu", {
3361 value: (oAttributes.lazyloadmenu === false ? false : true),
3362 validator: Lang.isBoolean,
3369 * @attribute menuclassname
3370 * @description String representing the CSS class name to be
3371 * applied to the root element of the button's menu.
3373 * @default "yui-button-menu"
3376 this.setAttributeConfig("menuclassname", {
3378 value: (oAttributes.menuclassname || "yui-button-menu"),
3379 validator: Lang.isString,
3380 method: this._setMenuClassName,
3387 * @attribute menuminscrollheight
3388 * @description Number defining the minimum threshold for the "menumaxheight"
3389 * configuration attribute. When set this attribute is automatically applied
3394 this.setAttributeConfig("menuminscrollheight", {
3396 value: (oAttributes.menuminscrollheight || 90),
3397 validator: Lang.isNumber
3403 * @attribute menumaxheight
3404 * @description Number defining the maximum height (in pixels) for a menu's
3405 * body element (<code><div class="bd"<</code>). Once a menu's body
3406 * exceeds this height, the contents of the body are scrolled to maintain
3407 * this value. This value cannot be set lower than the value of the
3408 * "minscrollheight" configuration property.
3412 this.setAttributeConfig("menumaxheight", {
3414 value: (oAttributes.menumaxheight || 0),
3415 validator: Lang.isNumber
3421 * @attribute menualignment
3422 * @description Array defining how the Button's Menu is aligned to the Button.
3423 * The default value of ["tl", "bl"] aligns the Menu's top left corner to the Button's
3424 * bottom left corner.
3426 * @default ["tl", "bl"]
3428 this.setAttributeConfig("menualignment", {
3430 value: (oAttributes.menualignment || ["tl", "bl"]),
3431 validator: Lang.isArray
3437 * @attribute selectedMenuItem
3438 * @description Object representing the item in the button's menu
3439 * that is currently selected.
3443 this.setAttributeConfig("selectedMenuItem", {
3451 * @attribute onclick
3452 * @description Object literal representing the code to be executed
3453 * when the button is clicked. Format:<br> <code> {<br>
3454 * <strong>fn:</strong> Function, // The handler to call
3455 * when the event fires.<br> <strong>obj:</strong> Object,
3456 * // An object to pass back to the handler.<br>
3457 * <strong>scope:</strong> Object // The object to use
3458 * for the scope of the handler.<br> } </code>
3462 this.setAttributeConfig("onclick", {
3464 value: oAttributes.onclick,
3465 method: this._setOnClick
3471 * @attribute focusmenu
3472 * @description Boolean indicating whether or not the button's menu
3473 * should be focused when it is made visible.
3477 this.setAttributeConfig("focusmenu", {
3479 value: (oAttributes.focusmenu === false ? false : true),
3480 validator: Lang.isBoolean
3489 * @description Causes the button to receive the focus and fires the
3490 * button's "focus" event.
3492 focus: function () {
3494 if (!this.get("disabled")) {
3496 this._button.focus();
3505 * @description Causes the button to lose focus and fires the button's
3510 if (!this.get("disabled")) {
3512 this._button.blur();
3521 * @description Returns a boolean indicating whether or not the button
3525 hasFocus: function () {
3527 return (m_oFocusedButton == this);
3534 * @description Returns a boolean indicating whether or not the button
3538 isActive: function () {
3540 return this.hasClass(this.CSS_CLASS_NAME + "-active");
3547 * @description Returns a reference to the button's menu.
3548 * @return {<a href="YAHOO.widget.Overlay.html">
3549 * YAHOO.widget.Overlay</a>|<a
3550 * href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
3552 getMenu: function () {
3561 * @description Returns a reference to the button's parent form.
3562 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-
3563 * 20000929/level-one-html.html#ID-40002357">HTMLFormElement</a>}
3565 getForm: function () {
3567 var oButton = this._button,
3572 oForm = oButton.form;
3582 * @method getHiddenFields
3583 * @description Returns an <code><input></code> element or
3584 * array of form elements used to represent the button when its parent
3585 * form is submitted.
3586 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3587 * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
3589 getHiddenFields: function () {
3591 return this._hiddenFields;
3598 * @description Removes the button's element from its parent element and
3599 * removes all event handlers.
3601 destroy: function () {
3603 YAHOO.log("Destroying ...", "info", this.toString());
3605 var oElement = this.get("element"),
3606 oParentNode = oElement.parentNode,
3612 YAHOO.log("Destroying menu.", "info", this.toString());
3614 if (m_oOverlayManager && m_oOverlayManager.find(oMenu)) {
3616 m_oOverlayManager.remove(oMenu);
3624 YAHOO.log("Removing DOM event listeners.", "info", this.toString());
3626 Event.purgeElement(oElement);
3627 Event.purgeElement(this._button);
3628 Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
3629 Event.removeListener(document, "keyup", this._onDocumentKeyUp);
3630 Event.removeListener(document, "mousedown", this._onDocumentMouseDown);
3633 var oForm = this.getForm();
3637 Event.removeListener(oForm, "reset", this._onFormReset);
3638 Event.removeListener(oForm, "submit", this._onFormSubmit);
3642 YAHOO.log("Removing CustomEvent listeners.", "info", this.toString());
3644 this.unsubscribeAll();
3648 oParentNode.removeChild(oElement);
3652 YAHOO.log("Removing from document.", "info", this.toString());
3654 delete m_oButtons[this.get("id")];
3656 aButtons = Dom.getElementsByClassName(this.CSS_CLASS_NAME,
3657 this.NODE_NAME, oForm);
3659 if (Lang.isArray(aButtons) && aButtons.length === 0) {
3661 Event.removeListener(oForm, "keypress",
3662 YAHOO.widget.Button.onFormKeyPress);
3666 YAHOO.log("Destroyed.", "info", this.toString());
3671 fireEvent: function (p_sType , p_aArgs) {
3673 var sType = arguments[0];
3675 // Disabled buttons should not respond to DOM events
3677 if (this.DOM_EVENTS[sType] && this.get("disabled")) {
3683 return YAHOO.widget.Button.superclass.fireEvent.apply(this, arguments);
3690 * @description Returns a string representing the button.
3693 toString: function () {
3695 return ("Button " + this.get("id"));
3703 * @method YAHOO.widget.Button.onFormKeyPress
3704 * @description "keypress" event handler for the button's form.
3705 * @param {Event} p_oEvent Object representing the DOM event object passed
3706 * back by the event utility (YAHOO.util.Event).
3708 YAHOO.widget.Button.onFormKeyPress = function (p_oEvent) {
3710 var oTarget = Event.getTarget(p_oEvent),
3711 nCharCode = Event.getCharCode(p_oEvent),
3712 sNodeName = oTarget.nodeName && oTarget.nodeName.toUpperCase(),
3713 sType = oTarget.type,
3716 Boolean indicating if the form contains any enabled or
3717 disabled YUI submit buttons
3720 bFormContainsYUIButtons = false,
3724 oYUISubmitButton, // The form's first, enabled YUI submit button
3727 The form's first, enabled HTML submit button that precedes any
3731 oPrecedingSubmitButton,
3736 function isSubmitButton(p_oElement) {
3741 switch (p_oElement.nodeName.toUpperCase()) {
3746 if (p_oElement.type == "submit" && !p_oElement.disabled) {
3748 if (!bFormContainsYUIButtons && !oPrecedingSubmitButton) {
3750 oPrecedingSubmitButton = p_oElement;
3761 sId = p_oElement.id;
3765 oButton = m_oButtons[sId];
3769 bFormContainsYUIButtons = true;
3771 if (!oButton.get("disabled")) {
3773 oSrcElement = oButton.get("srcelement");
3775 if (!oYUISubmitButton && (oButton.get("type") == "submit" ||
3776 (oSrcElement && oSrcElement.type == "submit"))) {
3778 oYUISubmitButton = oButton;
3795 if (nCharCode == 13 && ((sNodeName == "INPUT" && (sType == "text" ||
3796 sType == "password" || sType == "checkbox" || sType == "radio" ||
3797 sType == "file")) || sNodeName == "SELECT")) {
3799 Dom.getElementsBy(isSubmitButton, "*", this);
3802 if (oPrecedingSubmitButton) {
3805 Need to set focus to the first enabled submit button
3806 to make sure that IE includes its name and value
3807 in the form's data set.
3810 oPrecedingSubmitButton.focus();
3813 else if (!oPrecedingSubmitButton && oYUISubmitButton) {
3816 Need to call "preventDefault" to ensure that the form doesn't end up getting
3820 Event.preventDefault(p_oEvent);
3825 oYUISubmitButton.get("element").fireEvent("onclick");
3830 oEvent = document.createEvent("HTMLEvents");
3831 oEvent.initEvent("click", true, true);
3834 if (UA.gecko < 1.9) {
3836 oYUISubmitButton.fireEvent("click", oEvent);
3841 oYUISubmitButton.get("element").dispatchEvent(oEvent);
3855 * @method YAHOO.widget.Button.addHiddenFieldsToForm
3856 * @description Searches the specified form and adds hidden fields for
3857 * instances of YAHOO.widget.Button that are of type "radio," "checkbox,"
3858 * "menu," and "split."
3859 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3860 * one-html.html#ID-40002357">HTMLFormElement</a>} p_oForm Object reference
3861 * for the form to search.
3863 YAHOO.widget.Button.addHiddenFieldsToForm = function (p_oForm) {
3865 var aButtons = Dom.getElementsByClassName(
3866 YAHOO.widget.Button.prototype.CSS_CLASS_NAME,
3870 nButtons = aButtons.length,
3877 YAHOO.log("Form contains " + nButtons + " YUI buttons.", "info", this.toString());
3879 for (i = 0; i < nButtons; i++) {
3881 sId = aButtons[i].id;
3885 oButton = m_oButtons[sId];
3889 oButton.createHiddenFields();
3903 * @method YAHOO.widget.Button.getButton
3904 * @description Returns a button with the specified id.
3905 * @param {String} p_sId String specifying the id of the root node of the
3906 * HTML element representing the button to be retrieved.
3907 * @return {YAHOO.widget.Button}
3909 YAHOO.widget.Button.getButton = function (p_sId) {
3911 return m_oButtons[p_sId];
3921 * @description Fires when the menu item receives focus. Passes back a
3922 * single object representing the original DOM event object passed back by
3923 * the event utility (YAHOO.util.Event) when the event was fired. See
3924 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3925 * for more information on listening for this event.
3926 * @type YAHOO.util.CustomEvent
3932 * @description Fires when the menu item loses the input focus. Passes back
3933 * a single object representing the original DOM event object passed back by
3934 * the event utility (YAHOO.util.Event) when the event was fired. See
3935 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for
3936 * more information on listening for this event.
3937 * @type YAHOO.util.CustomEvent
3943 * @description Fires when the user invokes the button's option. Passes
3944 * back a single object representing the original DOM event (either
3945 * "mousedown" or "keydown") that caused the "option" event to fire. See
3946 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
3947 * for more information on listening for this event.
3948 * @type YAHOO.util.CustomEvent
3954 // Shorthard for utilities
3956 var Dom = YAHOO.util.Dom,
3957 Event = YAHOO.util.Event,
3959 Button = YAHOO.widget.Button,
3961 // Private collection of radio buttons
3968 * The ButtonGroup class creates a set of buttons that are mutually
3969 * exclusive; checking one button in the set will uncheck all others in the
3971 * @param {String} p_oElement String specifying the id attribute of the
3972 * <code><div></code> element of the button group.
3973 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3974 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
3975 * specifying the <code><div></code> element of the button group.
3976 * @param {Object} p_oElement Object literal specifying a set of
3977 * configuration attributes used to create the button group.
3978 * @param {Object} p_oAttributes Optional. Object literal specifying a set
3979 * of configuration attributes used to create the button group.
3980 * @namespace YAHOO.widget
3981 * @class ButtonGroup
3983 * @extends YAHOO.util.Element
3985 YAHOO.widget.ButtonGroup = function (p_oElement, p_oAttributes) {
3987 var fnSuperClass = YAHOO.widget.ButtonGroup.superclass.constructor,
3992 if (arguments.length == 1 && !Lang.isString(p_oElement) &&
3993 !p_oElement.nodeName) {
3995 if (!p_oElement.id) {
3997 sId = Dom.generateId();
3999 p_oElement.id = sId;
4001 YAHOO.log("No value specified for the button group's \"id\"" +
4002 " attribute. Setting button group id to \"" + sId + "\".",
4007 this.logger = new YAHOO.widget.LogWriter("ButtonGroup " + sId);
4009 this.logger.log("No source HTML element. Building the button " +
4010 "group using the set of configuration attributes.");
4012 fnSuperClass.call(this, (this._createGroupElement()), p_oElement);
4015 else if (Lang.isString(p_oElement)) {
4017 oElement = Dom.get(p_oElement);
4021 if (oElement.nodeName.toUpperCase() == this.NODE_NAME) {
4024 new YAHOO.widget.LogWriter("ButtonGroup " + p_oElement);
4026 fnSuperClass.call(this, oElement, p_oAttributes);
4035 sNodeName = p_oElement.nodeName.toUpperCase();
4037 if (sNodeName && sNodeName == this.NODE_NAME) {
4039 if (!p_oElement.id) {
4041 p_oElement.id = Dom.generateId();
4043 YAHOO.log("No value specified for the button group's" +
4044 " \"id\" attribute. Setting button group id " +
4045 "to \"" + p_oElement.id + "\".", "warn");
4050 new YAHOO.widget.LogWriter("ButtonGroup " + p_oElement.id);
4052 fnSuperClass.call(this, p_oElement, p_oAttributes);
4061 YAHOO.extend(YAHOO.widget.ButtonGroup, YAHOO.util.Element, {
4064 // Protected properties
4068 * @property _buttons
4069 * @description Array of buttons in the button group.
4082 * @property NODE_NAME
4083 * @description The name of the tag to be used for the button
4093 * @property CSS_CLASS_NAME
4094 * @description String representing the CSS class(es) to be applied
4095 * to the button group's element.
4096 * @default "yui-buttongroup"
4100 CSS_CLASS_NAME: "yui-buttongroup",
4104 // Protected methods
4108 * @method _createGroupElement
4109 * @description Creates the button group's element.
4111 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4112 * level-one-html.html#ID-22445964">HTMLDivElement</a>}
4114 _createGroupElement: function () {
4116 var oElement = document.createElement(this.NODE_NAME);
4124 // Protected attribute setter methods
4128 * @method _setDisabled
4129 * @description Sets the value of the button groups's
4130 * "disabled" attribute.
4132 * @param {Boolean} p_bDisabled Boolean indicating the value for
4133 * the button group's "disabled" attribute.
4135 _setDisabled: function (p_bDisabled) {
4137 var nButtons = this.getCount(),
4146 this._buttons[i].set("disabled", p_bDisabled);
4157 // Protected event handlers
4161 * @method _onKeyDown
4162 * @description "keydown" event handler for the button group.
4164 * @param {Event} p_oEvent Object representing the DOM event object
4165 * passed back by the event utility (YAHOO.util.Event).
4167 _onKeyDown: function (p_oEvent) {
4169 var oTarget = Event.getTarget(p_oEvent),
4170 nCharCode = Event.getCharCode(p_oEvent),
4171 sId = oTarget.parentNode.parentNode.id,
4172 oButton = m_oButtons[sId],
4176 if (nCharCode == 37 || nCharCode == 38) {
4178 nIndex = (oButton.index === 0) ?
4179 (this._buttons.length - 1) : (oButton.index - 1);
4182 else if (nCharCode == 39 || nCharCode == 40) {
4184 nIndex = (oButton.index === (this._buttons.length - 1)) ?
4185 0 : (oButton.index + 1);
4193 this.getButton(nIndex).focus();
4201 * @method _onAppendTo
4202 * @description "appendTo" event handler for the button group.
4204 * @param {Event} p_oEvent Object representing the event that was fired.
4206 _onAppendTo: function (p_oEvent) {
4208 var aButtons = this._buttons,
4209 nButtons = aButtons.length,
4212 for (i = 0; i < nButtons; i++) {
4214 aButtons[i].appendTo(this.get("element"));
4222 * @method _onButtonCheckedChange
4223 * @description "checkedChange" event handler for each button in the
4226 * @param {Event} p_oEvent Object representing the event that was fired.
4227 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4228 * p_oButton Object representing the button that fired the event.
4230 _onButtonCheckedChange: function (p_oEvent, p_oButton) {
4232 var bChecked = p_oEvent.newValue,
4233 oCheckedButton = this.get("checkedButton");
4235 if (bChecked && oCheckedButton != p_oButton) {
4237 if (oCheckedButton) {
4239 oCheckedButton.set("checked", false, true);
4243 this.set("checkedButton", p_oButton);
4244 this.set("value", p_oButton.get("value"));
4247 else if (oCheckedButton && !oCheckedButton.set("checked")) {
4249 oCheckedButton.set("checked", true, true);
4262 * @description The ButtonGroup class's initialization method.
4263 * @param {String} p_oElement String specifying the id attribute of the
4264 * <code><div></code> element of the button group.
4265 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4266 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
4267 * specifying the <code><div></code> element of the button group.
4268 * @param {Object} p_oElement Object literal specifying a set of
4269 * configuration attributes used to create the button group.
4270 * @param {Object} p_oAttributes Optional. Object literal specifying a
4271 * set of configuration attributes used to create the button group.
4273 init: function (p_oElement, p_oAttributes) {
4277 YAHOO.widget.ButtonGroup.superclass.init.call(this, p_oElement,
4280 this.addClass(this.CSS_CLASS_NAME);
4282 this.logger.log("Searching for child nodes with the class name " +
4283 "\"yui-radio-button\" to add to the button group.");
4285 var aButtons = this.getElementsByClassName("yui-radio-button");
4288 if (aButtons.length > 0) {
4290 this.logger.log("Found " + aButtons.length +
4291 " child nodes with the class name \"yui-radio-button.\"" +
4292 " Attempting to add to button group.");
4294 this.addButtons(aButtons);
4299 this.logger.log("Searching for child nodes with the type of " +
4300 " \"radio\" to add to the button group.");
4302 function isRadioButton(p_oElement) {
4304 return (p_oElement.type == "radio");
4309 Dom.getElementsBy(isRadioButton, "input", this.get("element"));
4312 if (aButtons.length > 0) {
4314 this.logger.log("Found " + aButtons.length + " child nodes" +
4315 " with the type of \"radio.\" Attempting to add to" +
4318 this.addButtons(aButtons);
4322 this.on("keydown", this._onKeyDown);
4323 this.on("appendTo", this._onAppendTo);
4326 var oContainer = this.get("container");
4330 if (Lang.isString(oContainer)) {
4332 Event.onContentReady(oContainer, function () {
4334 this.appendTo(oContainer);
4341 this.appendTo(oContainer);
4348 this.logger.log("Initialization completed.");
4354 * @method initAttributes
4355 * @description Initializes all of the configuration attributes used to
4356 * create the button group.
4357 * @param {Object} p_oAttributes Object literal specifying a set of
4358 * configuration attributes used to create the button group.
4360 initAttributes: function (p_oAttributes) {
4362 var oAttributes = p_oAttributes || {};
4364 YAHOO.widget.ButtonGroup.superclass.initAttributes.call(
4370 * @description String specifying the name for the button group.
4371 * This name will be applied to each button in the button group.
4375 this.setAttributeConfig("name", {
4377 value: oAttributes.name,
4378 validator: Lang.isString
4384 * @attribute disabled
4385 * @description Boolean indicating if the button group should be
4386 * disabled. Disabling the button group will disable each button
4387 * in the button group. Disabled buttons are dimmed and will not
4388 * respond to user input or fire events.
4392 this.setAttributeConfig("disabled", {
4394 value: (oAttributes.disabled || false),
4395 validator: Lang.isBoolean,
4396 method: this._setDisabled
4403 * @description Object specifying the value for the button group.
4407 this.setAttributeConfig("value", {
4409 value: oAttributes.value
4415 * @attribute container
4416 * @description HTML element reference or string specifying the id
4417 * attribute of the HTML element that the button group's markup
4418 * should be rendered into.
4419 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4420 * level-one-html.html#ID-58190037">HTMLElement</a>|String
4424 this.setAttributeConfig("container", {
4426 value: oAttributes.container,
4433 * @attribute checkedButton
4434 * @description Reference for the button in the button group that
4436 * @type {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4439 this.setAttributeConfig("checkedButton", {
4450 * @description Adds the button to the button group.
4451 * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4452 * p_oButton Object reference for the <a href="YAHOO.widget.Button.html">
4453 * YAHOO.widget.Button</a> instance to be added to the button group.
4454 * @param {String} p_oButton String specifying the id attribute of the
4455 * <code><input></code> or <code><span></code> element
4456 * to be used to create the button to be added to the button group.
4457 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4458 * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="
4459 * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
4460 * ID-33759296">HTMLElement</a>} p_oButton Object reference for the
4461 * <code><input></code> or <code><span></code> element
4462 * to be used to create the button to be added to the button group.
4463 * @param {Object} p_oButton Object literal specifying a set of
4464 * <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4465 * configuration attributes used to configure the button to be added to
4467 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4469 addButton: function (p_oButton) {
4479 if (p_oButton instanceof Button &&
4480 p_oButton.get("type") == "radio") {
4482 oButton = p_oButton;
4485 else if (!Lang.isString(p_oButton) && !p_oButton.nodeName) {
4487 p_oButton.type = "radio";
4489 oButton = new Button(p_oButton);
4494 oButton = new Button(p_oButton, { type: "radio" });
4501 nIndex = this._buttons.length;
4502 sButtonName = oButton.get("name");
4503 sGroupName = this.get("name");
4505 oButton.index = nIndex;
4507 this._buttons[nIndex] = oButton;
4508 m_oButtons[oButton.get("id")] = oButton;
4511 if (sButtonName != sGroupName) {
4513 oButton.set("name", sGroupName);
4518 if (this.get("disabled")) {
4520 oButton.set("disabled", true);
4525 if (oButton.get("checked")) {
4527 this.set("checkedButton", oButton);
4532 oButtonElement = oButton.get("element");
4533 oGroupElement = this.get("element");
4535 if (oButtonElement.parentNode != oGroupElement) {
4537 oGroupElement.appendChild(oButtonElement);
4542 oButton.on("checkedChange",
4543 this._onButtonCheckedChange, oButton, this);
4545 this.logger.log("Button " + oButton.get("id") + " added.");
4555 * @method addButtons
4556 * @description Adds the array of buttons to the button group.
4557 * @param {Array} p_aButtons Array of <a href="YAHOO.widget.Button.html">
4558 * YAHOO.widget.Button</a> instances to be added
4559 * to the button group.
4560 * @param {Array} p_aButtons Array of strings specifying the id
4561 * attribute of the <code><input></code> or <code><span>
4562 * </code> elements to be used to create the buttons to be added to the
4564 * @param {Array} p_aButtons Array of object references for the
4565 * <code><input></code> or <code><span></code> elements
4566 * to be used to create the buttons to be added to the button group.
4567 * @param {Array} p_aButtons Array of object literals, each containing
4568 * a set of <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>
4569 * configuration attributes used to configure each button to be added
4570 * to the button group.
4573 addButtons: function (p_aButtons) {
4580 if (Lang.isArray(p_aButtons)) {
4582 nButtons = p_aButtons.length;
4587 for (i = 0; i < nButtons; i++) {
4589 oButton = this.addButton(p_aButtons[i]);
4593 aButtons[aButtons.length] = oButton;
4609 * @method removeButton
4610 * @description Removes the button at the specified index from the
4612 * @param {Number} p_nIndex Number specifying the index of the button
4613 * to be removed from the button group.
4615 removeButton: function (p_nIndex) {
4617 var oButton = this.getButton(p_nIndex),
4623 this.logger.log("Removing button " + oButton.get("id") + ".");
4625 this._buttons.splice(p_nIndex, 1);
4626 delete m_oButtons[oButton.get("id")];
4628 oButton.removeListener("checkedChange",
4629 this._onButtonCheckedChange);
4634 nButtons = this._buttons.length;
4638 i = this._buttons.length - 1;
4642 this._buttons[i].index = i;
4649 this.logger.log("Button " + oButton.get("id") + " removed.");
4658 * @description Returns the button at the specified index.
4659 * @param {Number} p_nIndex The index of the button to retrieve from the
4661 * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
4663 getButton: function (p_nIndex) {
4665 return this._buttons[p_nIndex];
4671 * @method getButtons
4672 * @description Returns an array of the buttons in the button group.
4675 getButtons: function () {
4677 return this._buttons;
4684 * @description Returns the number of buttons in the button group.
4687 getCount: function () {
4689 return this._buttons.length;
4696 * @description Sets focus to the button at the specified index.
4697 * @param {Number} p_nIndex Number indicating the index of the button
4700 focus: function (p_nIndex) {
4706 if (Lang.isNumber(p_nIndex)) {
4708 oButton = this._buttons[p_nIndex];
4719 nButtons = this.getCount();
4721 for (i = 0; i < nButtons; i++) {
4723 oButton = this._buttons[i];
4725 if (!oButton.get("disabled")) {
4741 * @description Checks the button at the specified index.
4742 * @param {Number} p_nIndex Number indicating the index of the button
4745 check: function (p_nIndex) {
4747 var oButton = this.getButton(p_nIndex);
4751 oButton.set("checked", true);
4760 * @description Removes the button group's element from its parent
4761 * element and removes all event handlers.
4763 destroy: function () {
4765 this.logger.log("Destroying...");
4767 var nButtons = this._buttons.length,
4768 oElement = this.get("element"),
4769 oParentNode = oElement.parentNode,
4774 i = this._buttons.length - 1;
4778 this._buttons[i].destroy();
4785 this.logger.log("Removing DOM event handlers.");
4787 Event.purgeElement(oElement);
4789 this.logger.log("Removing from document.");
4791 oParentNode.removeChild(oElement);
4798 * @description Returns a string representing the button group.
4801 toString: function () {
4803 return ("ButtonGroup " + this.get("id"));
4810 YAHOO.register("button", YAHOO.widget.Button, {version: "2.7.0", build: "1799"});