/* * ***** BEGIN LICENSE BLOCK ***** * Version: ZAPL 1.1 * * The contents of this file are subject to the Zimbra AJAX Public * License Version 1.1 ("License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.zimbra.com/license * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is: Zimbra AJAX Toolkit. * * The Initial Developer of the Original Code is Zimbra, Inc. * Portions created by Zimbra are Copyright (C) 2005 Zimbra, Inc. * All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** */ /** * Creates a button. * @constructor * @class * This class represents a button, which is basically a smart label that can handle * various UI events. It knows when it has been activated (the mouse is over it), * when it has been triggered (mouse down), and when it has been pressed (mouse up). * In addition to a label's image and/or text, a button may have a dropdown menu. * * @author Ross Dargahi * @author Conrad Damon * @param parent the parent widget * @param style the label style (see DwtLabel) * @param className a CSS class * @param posStyle positioning style */ function DwtButton(parent, style, className, posStyle, actionTiming) { if (arguments.length == 0) return; className = className || "DwtButton"; DwtLabel.call(this, parent, style, className, posStyle); // CSS classes to handle activated/triggered states this._origClassName = className; this._activatedClassName = this._className + "-" + DwtCssStyle.ACTIVATED; this._triggeredClassName = this._className + "-" + DwtCssStyle.TRIGGERED; this._toggledClassName = this._className + "-" + DwtCssStyle.TOGGLED; // add custom mouse handlers to standard ones this._setMouseEventHdlrs(); this._setIERolloverEventHdlrs(); this._setKeyEventHdlrs(); this._mouseOverListener = new AjxListener(this, DwtButton.prototype._mouseOverListener); this._mouseOutListener = new AjxListener(this, DwtButton.prototype._mouseOutListener); this._mouseDownListener = new AjxListener(this, DwtButton.prototype._mouseDownListener); this._mouseUpListener = new AjxListener(this, DwtButton.prototype._mouseUpListener); this._addMouseListeners(); this._dropDownEvtMgr = new AjxEventMgr(); this._toggled = false; this._actionTiming = actionTiming? actionTiming : DwtButton.ACTION_MOUSEUP; } DwtButton.prototype = new DwtLabel; DwtButton.prototype.constructor = DwtButton; DwtButton.TOGGLE_STYLE = DwtLabel._LAST_STYLE * 2; DwtButton.ACTION_MOUSEUP = 1; DwtButton.ACTION_MOUSEDOWN = 2; // Public methods DwtButton.prototype.toString = function() { return "DwtButton"; } /** * Adds a listener to be notified when the button is pressed. * * @param listener a listener */ DwtButton.prototype.addSelectionListener = function(listener) { this.addListener(DwtEvent.SELECTION, listener); } /** * Removes a selection listener. * * @param listener the listener to remove */ DwtButton.prototype.removeSelectionListener = function(listener) { this.removeListener(DwtEvent.SELECTION, listener); } /** * Removes all the selection listeners. */ DwtButton.prototype.removeSelectionListeners = function() { this.removeAllListeners(DwtEvent.SELECTION); } /** * Adds a listener to be notified when the dropdown arrow is pressed. * * @param listener a listener */ DwtButton.prototype.addDropDownSelectionListener = function(listener) { this._dropDownEvtMgr.addListener(DwtEvent.SELECTION, listener); } /** * Removes a dropdown selection listener. * * @param listener the listener to remove */ DwtButton.prototype.removeDropDownSelectionListener = function(listener) { this._dropDownEvtMgr.removeListener(DwtEvent.SELECTION, listener); } DwtButton.prototype.setDropDownImages = function (enabledImg, disImg, hovImg, depImg) { this._dropDownImg = enabledImg; this._dropDownDisImg = disImg; this._dropDownHovImg = hovImg; this._dropDownDepImg = depImg; }; /** * add all mouse listeners for our widget - this uses mouseenter and mouseleave * for IE. */ DwtButton.prototype._addMouseListeners = function() { if (AjxEnv.isIE) { this.addListener(DwtEvent.ONMOUSEENTER, this._mouseOverListener); } else { this.addListener(DwtEvent.ONMOUSEOVER, this._mouseOverListener); } if (AjxEnv.isIE) { this.addListener(DwtEvent.ONMOUSELEAVE, this._mouseOutListener); } else { this.addListener(DwtEvent.ONMOUSEOUT, this._mouseOutListener); } this.addListener(DwtEvent.ONMOUSEDOWN, this._mouseDownListener); this.addListener(DwtEvent.ONMOUSEUP, this._mouseUpListener); }; /** * remove all mouse listeners from our widget */ DwtButton.prototype._removeMouseListeners = function() { if (AjxEnv.isIE) { this.removeListener(DwtEvent.ONMOUSEENTER, this._mouseOverListener); } else { this.removeListener(DwtEvent.ONMOUSEOVER, this._mouseOverListener); } if (AjxEnv.isIE) { this.removeListener(DwtEvent.ONMOUSELEAVE, this._mouseOutListener); } else { this.removeListener(DwtEvent.ONMOUSEOUT, this._mouseOutListener); } this.removeListener(DwtEvent.ONMOUSEDOWN, this._mouseDownListener); this.removeListener(DwtEvent.ONMOUSEUP, this._mouseUpListener); }; /** * Sets the enabled/disabled state of the button. A disabled button may have a different * image, and greyed out text. The button (and its menu) will only have listeners if it * is enabled. * * @param enabled whether to enable the button * */ DwtButton.prototype.setEnabled = function(enabled) { if (enabled != this._enabled) { DwtLabel.prototype.setEnabled.call(this, enabled); // handles image/text if (enabled) { this._addMouseListeners(); // set event handler for pull down menu if applicable if (this._menu) { this._setupDropDownCellMouseHandlers(); AjxImg.setImage(this._dropDownCell, this._dropDownImg); } } else { this.setClassName(this._origClassName); // clear activated or triggered this._removeMouseListeners(); // remove event handlers for pull down menu if applicable if (this._menu) { this._removeDropDownCellMouseHandlers(); AjxImg.setImage(this._dropDownCell, this._dropDownDisImg); } } } } DwtButton.prototype.setHoverImage = function (hoverImageInfo) { this._hoverImageInfo = hoverImageInfo; } /** * Adds a dropdown menu to the button, available through a small down-arrow. * * @param menu the dropdown menu * @param shouldToggle * @param followIconStyle style of menu item (should be checked or radio style) for * which the button icon should reflect the menu item icon */ DwtButton.prototype.setMenu = function(menu, shouldToggle, followIconStyle) { this._menu = menu; this._shouldToggleMenu = (shouldToggle === true); this._followIconStyle = followIconStyle; if (menu && !this._dropDownCell) { var idx = (this._imageCell) ? 1 : 0; if (this._textCell) idx++; this._dropDownCell = this._row.insertCell(idx); this._dropDownCell.id = Dwt.getNextId(); this._dropDownCell.className = "dropDownCell"; if (this._dropDownImg == null) this._dropDownImg = DwtImg.SELECT_PULL_DOWN; if (this._dropDownDisImg == null) this._dropDownDisImg = DwtImg.SELECT_PULL_DOWN_DISABLED; if (this._dropDownHovImg == null) this._dropDownHovImg = DwtImg.SELECT_PULL_DOWN_ENABLED; AjxImg.setImage(this._dropDownCell, this._dropDownImg); this._menu.setAssociatedElementId(this._dropDownCell.id); // set event handler if applicable if (this._enabled) { this._setupDropDownCellMouseHandlers(); } } else if (!menu && this._dropDownCell) { this._row.deleteCell(this._dropDownCell.cellIndex); this._dropDownCell = null; } } DwtButton.prototype._setupDropDownCellMouseHandlers = function () { this._dropDownCell.onmousedown = DwtButton._dropDownCellMouseDownHdlr; this._dropDownCell.onmouseup = DwtButton._dropDownCellMouseUpHdlr; }; DwtButton.prototype._removeDropDownCellMouseHandlers = function () { this._dropDownCell.onmousedown = null; this._dropDownCell.onmouseup = null; }; /** * Returns the button's menu */ DwtButton.prototype.getMenu = function() { return this._menu; } /** * Returns the button display to normal (not activated or triggered). */ DwtButton.prototype.resetClassName = function() { this.setClassName(this._origClassName); } /* * Sets whether actions for this button should occur on mouse up or mouse * down. * * Currently supports DwtButton.ACTION_MOUSEDOWN and DwtButton.ACTION_MOUSEUP */ DwtButton.prototype.setActionTiming = function(actionTiming) { this._actionTiming = actionTiming; }; /** * Activates/inactivates the button. A button is activated when the mouse is over it. * * @param activated whether the button is activated */ DwtButton.prototype.setActivated = function(activated) { if (activated) { this.setClassName(this._activatedClassName); } else { this.setClassName(this._origClassName); } } DwtButton.prototype.setEnabledImage = function (imageInfo) { this._enabledImageInfo = imageInfo; this.setImage(imageInfo); } DwtButton.prototype.setDepressedImage = function (imageInfo) { this._depressedImageInfo = imageInfo; } DwtButton.prototype.setToggled = function(toggled) { if ((this._style & DwtButton.TOGGLE_STYLE) && this._toggled != toggled) { this._toggled = toggled; this.setClassName((toggled) ? this._toggledClassName : this._origClassName); } } // Private methods DwtButton.prototype._toggleMenu = function () { if (this._shouldToggleMenu){ if (!this._menu.isPoppedup()){ this._menu.popup(); this._menuUp = true; } else { this._menu.popdown(); this._menuUp = false; } } else { this._menu.popup(); } }; // Activates the button. DwtButton.prototype._mouseOverListener = function(ev) { if (this._hoverImageInfo) { this.setImage(this._hoverImageInfo); } this.setClassName(this._activatedClassName); if (this._dropDownCell && this._dropDownHovImg && !this.noMenuBar) { AjxImg.setImage(this._dropDownCell, this._dropDownHovImg); } ev._stopPropagation = true; } // Triggers the button. DwtButton.prototype._mouseDownListener = function(ev) { if (this._dropDownCell && this._dropDownDepImg) { AjxImg.setImage(this._dropDownCell, this._dropDownDepImg); } switch (this._actionTiming) { case DwtButton.ACTION_MOUSEDOWN: var el = this.getHtmlElement(); this.trigger(); if (this.isListenerRegistered(DwtEvent.SELECTION)) { var selEv = DwtShell.selectionEvent; DwtUiEvent.copy(selEv, ev); selEv.item = this; selEv.detail = 0; this.notifyListeners(DwtEvent.SELECTION, selEv); } else if (this._menu) { this._toggleMenu(); } // So that listeners may remove this object from the flow, and not // get errors, when DwtControl tries to do a this.getHtmlElement () // ROSSD - I don't get this, basically this method does a // this.getHtmlElement as the first thing it does // so why would the line below cause a problem. It does have the // side-effect of making buttons behave weirdly // in that they will not remain active on mouse up //el.className = this._origClassName; break; case DwtButton.ACTION_MOUSEUP: this.trigger(); break; } } DwtButton.prototype.trigger = function (){ if (this._depressedImageInfo) { this.setImage(this._depressedImageInfo); } this.setClassName(this._triggeredClassName); this.isTriggered = true; }; DwtButton.prototype.deactivate = function (){ if (this._depressedImageInfo){ this.setImage(this._hoverImageInfo); } if (this._style & DwtButton.TOGGLE_STYLE){ this._toggled = !this._toggled; } this.setClassName((!this._toggled) ? this._activatedClassName : this._toggledClassName); }; // Button has been pressed, notify selection listeners. DwtButton.prototype._mouseUpListener = function(ev) { if (this._dropDownCell && this._dropDownHovImg && !this.noMenuBar){ AjxImg.setImage(this._dropDownCell, this._dropDownHovImg); } switch (this._actionTiming) { case DwtButton.ACTION_MOUSEDOWN: this.deactivate(); break; case DwtButton.ACTION_MOUSEUP: var el = this.getHtmlElement(); if (this.isTriggered) { this.deactivate(); if (this.isListenerRegistered(DwtEvent.SELECTION)) { var selEv = DwtShell.selectionEvent; DwtUiEvent.copy(selEv, ev); selEv.item = this; selEv.detail = 0; this.notifyListeners(DwtEvent.SELECTION, selEv); } else if (this._menu) { this._toggleMenu(); } } // So that listeners may remove this object from the flow, and not // get errors, when DwtControl tries to do a this.getHtmlElement() // ROSSD - I don't get this, basically this method does a this.getHtmlElement as the first thing it does // so why would the line below cause a problem. It does have the side-effect of making buttons behave weirdly // in that they will not remain active on mouse up //el.className = this._origClassName; break; } }; DwtButton.prototype._setMouseOutClassName = function() { this.setClassName((this._toggled) ? this._toggledClassName : this._origClassName); } // Button no longer activated/triggered. DwtButton.prototype._mouseOutListener = function(ev) { if (this._hoverImageInfo) { this.setImage(this._enabledImageInfo); } this._setMouseOutClassName(); this.isTriggered = false; if (this._dropDownCell){ AjxImg.setImage(this._dropDownCell, this._dropDownImg); } } // Pops up the dropdown menu. DwtButton._dropDownCellMouseDownHdlr = function(ev) { if (this._depImg){ AjxImg.setImage(this, this._depImg); } DwtEventManager.notifyListeners(DwtEvent.ONMOUSEDOWN, ev); var obj = DwtUiEvent.getDwtObjFromEvent(ev); var mouseEv = DwtShell.mouseEvent; mouseEv.setFromDhtmlEvent(ev); if (obj._dropDownEvtMgr.isListenerRegistered(DwtEvent.SELECTION)) { var selEv = DwtShell.selectionEvent; DwtUiEvent.copy(selEv, mouseEv); selEv.item = obj; obj._dropDownEvtMgr.notifyListeners(DwtEvent.SELECTION, selEv); } else if (mouseEv.button == DwtMouseEvent.LEFT) { obj._toggleMenu(); } mouseEv._stopPropagation = true; mouseEv._returnValue = false; mouseEv.setToDhtmlEvent(ev); return false; } // Updates the current mouse event (set from the previous mouse down). DwtButton._dropDownCellMouseUpHdlr = function(ev) { if (this._hovImg && !this.noMenuBar) { AjxImg.setImage(this, this._hovImg); } var obj = DwtUiEvent.getDwtObjFromEvent(ev); var mouseEv = DwtShell.mouseEvent; mouseEv.setFromDhtmlEvent(ev); mouseEv._stopPropagation = true; mouseEv._returnValue = false; mouseEv.setToDhtmlEvent(ev); return false; }