Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
rwt.widgets.Menu.js Maven / Gradle / Ivy
Go to download
The Rich Ajax Platform lets you build rich, Ajax-enabled Web applications.
/*******************************************************************************
* Copyright (c) 2009, 2012 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
rwt.qx.Class.define( "rwt.widgets.Menu", {
extend : rwt.widgets.base.Popup,
include : rwt.animation.VisibilityAnimationMixin,
construct : function() {
this.base( arguments );
this._layout = null;
this._preItem = null;
this._hasShowListener = false;
this._hasHideListener = false;
this._maxCellWidths = null;
this._menuLayoutScheduled = false;
this._opener = null;
this._hoverItem = null;
this._openTimer = null;
this._closeTimer = null;
this._openItem = null;
this._itemsHiddenFlag = false;
this._hoverFirstItemFlag = false;
this.setHeight( "auto" );
this.setWidth( "auto" );
this._maxCellWidths = [ null, null, null, null ];
this._layout = new rwt.widgets.base.VerticalBoxLayout();
this._layout.set( {
top : 0,
right : 0,
bottom : 0,
left : 0,
anonymous : true
} );
this.add( this._layout );
this.addEventListener( "mousedown", this._unhoverSubMenu );
this.addEventListener( "mouseout", this._onMouseOut );
this.addEventListener( "mouseover", this._onMouseOver );
this.addEventListener( "keypress", this._onKeyPress );
this._openTimer = new rwt.client.Timer( 250 );
this._openTimer.addEventListener( "interval", this._onopentimer, this );
this._closeTimer = new rwt.client.Timer( 250 );
this._closeTimer.addEventListener( "interval", this._onclosetimer, this );
this.addToDocument();
},
destruct : function() {
this._disposeObjects( "_openTimer", "_closeTimer", "_preItem", "_animation" );
this._disposeFields( "_lastActive",
"_lastFocus",
"_layout",
"_opener",
"_hoverItem",
"_openItem" );
},
statics : {
menuDetectedByKey : function( evt ) {
if( evt.getKeyIdentifier() === "Apps" ) {
rwt.widgets.Menu.contextMenuHandler( evt );
}
},
menuDetectedByMouse : function( evt ) {
if( evt.getButton() === rwt.event.MouseEvent.C_BUTTON_RIGHT ) {
rwt.widgets.Menu.contextMenuHandler( evt );
}
},
contextMenuHandler : function( event ) {
var control = rwt.widgets.util.WidgetUtil.getControl( event.getTarget() );
var contextMenu = control ? control.getContextMenu() : null;
if( contextMenu != null ) {
event.stopPropagation();
event.preventDefault();
var pageX = rwt.event.MouseEvent.getPageX();
var pageY = rwt.event.MouseEvent.getPageY();
contextMenu.setLocation( pageX, pageY );
contextMenu.setOpener( control );
contextMenu.show();
}
},
getAllowContextMenu : function( target, domTarget ) {
var result = false;
switch( target.classname ) {
case "rwt.widgets.Text":
case "rwt.widgets.base.BasicText":
case "qx.ui.form.TextArea":
// NOTE: "enabled" can be "inherit", so it is not always a boolean
if( target.getEnabled() !== false ) {
if( rwt.widgets.Menu._hasNativeMenu( domTarget ) ) {
result = target.getContextMenu() == null;
}
}
break;
}
return result;
},
_hasNativeMenu : function( element ) {
var tagName = typeof element.tagName == "string" ? element.tagName.toUpperCase() : "";
return tagName === "INPUT" || tagName === "TEXTAREA";
}
},
properties : {
appearance : {
refine : true,
init : "menu"
}
},
events : {
"changeHoverItem" : "rwt.event.Event"
},
members : {
/////////
// Opener
setOpener : function( value ) {
this._opener = value;
},
getOpener : function( value ) {
return this._opener;
},
// Overwritten:
getFocusRoot : function() {
var root = null;
if ( this._opener ) {
root = this._opener.getFocusRoot();
} else if( this._hasParent ) {
root = this.getParent().getFocusRoot();
}
return root;
},
/////////
// Layout
addMenuItemAt : function( menuItem, index ) {
// seperator does not have this function:
if( menuItem.setParentMenu ) {
// it is essential that this happens before the menuItem is added
menuItem.setParentMenu( this );
}
this._layout.addAt( menuItem, index );
},
scheduleMenuLayout : function() {
if( this._menuLayoutScheduled !== true ) {
this._menuLayoutScheduled = true;
var children = this._layout.getChildren();
var length = children.length;
for( var i = 0; i < length; i++ ) {
children[ i ]._invalidatePreferredInnerWidth();
children[ i ].addToQueue( "layoutX" );
}
this.addToQueue( "menuLayout" );
}
},
_layoutPost : function( changes ) {
this.base( arguments, changes );
if( changes.menuLayout ) {
this._menuLayoutScheduled = false;
if( this.isSeeable() ) {
this._afterAppear(); // recomputes the location
}
}
},
getMaxCellWidth : function( cell ) {
if( this._maxCellWidths[ cell ] == null ) {
var max = 0;
var children = this._layout.getChildren();
var length = children.length;
for( var i = 0; i < length; i++ ) {
if( children[ i ].getPreferredCellWidth ) {
max = Math.max( max, children[ i ].getPreferredCellWidth( cell ) );
}
}
this._maxCellWidths[ cell ] = max;
}
if( cell === 0 && this._maxCellWidths[ 0 ] === 0 && this.getMaxCellWidth( 1 ) === 0 ) {
this._maxCellWidths[ cell ] = 13;
}
return this._maxCellWidths[ cell ];
},
invalidateMaxCellWidth : function( cell ) {
this._maxCellWidths[ cell ] = null;
},
invalidateAllMaxCellWidths : function() {
for( var i = 0; i < 4; i++ ) {
this._maxCellWidths[ i ] = null;
}
},
// needed for the menu-manager:
isSubElement : function( vElement, vButtonsOnly ) {
var ret = false;
if ( ( vElement.getParent() === this._layout )
|| ( ( !vButtonsOnly ) && ( vElement === this ) ) ) {
ret = true;
}
if( !ret ) {
var a = this._layout.getChildren(), l=a.length;
for ( var i = 0; i < l; i++ ) {
if ( this.hasSubmenu( a[ i ] )
&& a[ i ].getMenu().isSubElement( vElement, vButtonsOnly ) )
{
ret = true;
}
}
}
return ret;
},
////////
// Hover
setHoverItem : function( value, fromKeyEvent ) {
var newHover = value ? value : this._openItem;
if( this._hoverItem && this._hoverItem != newHover ) {
this._hoverItem.removeState( "over" );
}
if( newHover ) {
newHover.addState( "over" );
}
this._hoverItem = newHover;
if( !fromKeyEvent ) {
// handle open timer
this._openTimer.setEnabled( false );
if( this.hasSubmenu( newHover ) && ( this._openItem != newHover ) ) {
this._openTimer.setEnabled( true );
}
// handle close tiemr
if( this._openItem ) {
if( this._openItem == newHover || newHover == null ) {
this._closeTimer.setEnabled( false );
} else if( newHover != null ) {
this._closeTimer.setEnabled( true );
}
}
}
this.dispatchSimpleEvent( "changeHoverItem" );
},
getHoverItem : function( value ) {
return this._hoverItem;
},
hoverFirstItem : function() {
if( this._isDisplayable && !this._itemsHiddenFlag ) {
this.setHoverItem( null, true );
this._hoverNextItem();
this.removeState( "hoverFristItem" );
} else {
this.addState( "hoverFristItem" );
}
},
_hoverNextItem : function() {
// About _hoverNext/Previous:
// the index used for the array of visible children can have
// "-1" as a valid value (as returned by indexOf), meaning a position
// between the last and the first item. This is value is needed when no
// item is hovered or the index-position is wrapping around.
var current;
var next = null;
var children = this._layout.getVisibleChildren();
var index = children.indexOf( this._hoverItem );
var startIndex = index;
do {
index++;
if( index > children.length ) {
index = -1;
}
current = index >= 0 ? children[ index ] : null;
if( current
&& current.isEnabled()
&& current.classname == "rwt.widgets.MenuItem" )
{
next = current;
}
} while( !next && ( index != startIndex ) );
this.setHoverItem( next, true );
},
_hoverPreviousItem : function() {
var current;
var prev = null;
var children = this._layout.getVisibleChildren();
var index = children.indexOf( this._hoverItem );
var startIndex = index;
do {
index--;
if( index < -1 ) {
index = children.length;
}
current = index >= 0 ? children[ index ] : null;
if( current
&& current.isEnabled()
&& current.classname == "rwt.widgets.MenuItem" )
{
prev = current;
}
} while( !prev && ( index != startIndex ) );
this.setHoverItem( prev, true );
},
//////////////////
// Pop-Up handling
// overwritten:
_makeActive : function() {
this._lastActive = this.getFocusRoot().getActiveChild();
this._lastFocus = this.getFocusRoot().getFocusedChild();
this.getFocusRoot().setActiveChild(this);
},
// overwritten:
_makeInactive : function() {
var vRoot = this.getFocusRoot();
vRoot.setActiveChild( this._lastActive );
vRoot.setFocusedChild( this._lastFocus );
},
_beforeAppear : function() {
// original qooxdoo code: (1 line)
rwt.widgets.base.Parent.prototype._beforeAppear.call( this );
rwt.widgets.util.MenuManager.getInstance().add( this );
this.bringToFront();
this._makeActive();
this._menuShown();
},
_beforeDisappear : function() {
// original qooxdoo code: (1 line)
rwt.widgets.base.Parent.prototype._beforeDisappear.call( this );
rwt.widgets.util.MenuManager.getInstance().remove( this );
if( this.getFocusRoot() ) {
// if the menu is disposed while visible, it might not have a focusRoot
this._makeInactive();
}
this.setOpenItem( null );
this.setHoverItem( null );
if( this._opener instanceof rwt.widgets.MenuItem ) {
var parentMenu = this._opener.getParentMenu();
if( parentMenu instanceof rwt.widgets.MenuBar ) {
this._opener.removeState( "pressed" );
if( parentMenu.getOpenItem() == this._opener ) {
parentMenu.setOpenItem( null );
}
}
}
this._menuHidden();
},
//////////
// Submenu
hasSubmenu : function( item ) {
return item && item.getMenu && item.getMenu();
},
_onopentimer : function( event ) {
this._openTimer.stop();
this.setOpenItem( this._hoverItem );
// fix for bug 299350
this._closeTimer.stop();
},
_onclosetimer : function( event ) {
this._closeTimer.stop();
this.setOpenItem( null );
},
setOpenItem : function( item ) {
if( this._openItem && this._openItem.getMenu() ) {
this._openItem.setSubMenuOpen( false );
var oldMenu = this._openItem.getMenu();
oldMenu.hide();
this._makeActive();
}
this._openItem = item;
// in theory an item could have lost it's assigned menu (by eval-code)
// since the timer has been started/the item opend, so check for it
if( item && item.getMenu() ) {
var subMenu = item.getMenu();
item.setSubMenuOpen( true );
subMenu.setOpener( item );
var itemNode = item.getElement();
var thisNode = this.getElement();
// the position is relative to the document, therefore we need helper
subMenu.setTop( rwt.html.Location.getTop( itemNode ) - 2 );
subMenu.setLeft( rwt.html.Location.getLeft( thisNode )
+ thisNode.offsetWidth
- 3 );
subMenu.show();
}
},
/////////////////
// Event-handling
_onMouseOut : function( event ) {
var target = event.getTarget();
var related = event.getRelatedTarget();
if ( target == this || ( related != this && !this.contains( related ) ) )
{
this.setHoverItem( null );
}
},
_onMouseOver : function( event ) {
var target = event.getTarget();
if( target != this ) {
this.setHoverItem( target );
}
this._unhoverSubMenu();
},
_unhoverSubMenu : function() {
if( this._openItem ) {
var subMenu = this._openItem.getMenu();
subMenu.setOpenItem( null );
subMenu.setHoverItem( null );
}
},
_onKeyPress : function( event ) {
switch( event.getKeyIdentifier() ) {
case "Up":
this._handleKeyUp( event );
break;
case "Down":
this._handleKeyDown( event );
break;
case "Left":
this._handleKeyLeft( event );
break;
case "Right":
this._handleKeyRight( event );
break;
case "Enter":
this._handleKeyEnter( event );
break;
}
},
_handleKeyUp : function( event ) {
if( this._openItem ) {
this._openItem.getMenu()._hoverPreviousItem();
} else {
this._hoverPreviousItem();
}
event.preventDefault();
event.stopPropagation();
},
_handleKeyDown : function( event ) {
if( this._openItem ) {
this._openItem.getMenu()._hoverNextItem();
} else {
this._hoverNextItem();
}
event.preventDefault();
event.stopPropagation();
},
_handleKeyLeft : function( event ) {
var parentMenu = this._opener ? this._opener.getParentMenu() : null;
if( parentMenu instanceof rwt.widgets.Menu ) {
var hover = this._opener;
parentMenu.setOpenItem( null );
parentMenu.setHoverItem( hover, true );
event.preventDefault();
event.stopPropagation();
}
},
_handleKeyRight : function( event ) {
if( this.hasSubmenu( this._hoverItem ) ) {
this._onopentimer();
this.setHoverItem( null, true );
this._openItem.getMenu().hoverFirstItem();
event.preventDefault();
event.stopPropagation();
}
},
_handleKeyEnter : function( event ) {
if( this.hasSubmenu( this._hoverItem ) ) {
this._onopentimer();
this.setHoverItem( null, true );
this._openItem.getMenu().hoverFirstItem();
} else if( this._hoverItem ){
this._hoverItem.execute();
rwt.widgets.util.MenuManager.getInstance().update();
}
event.preventDefault();
event.stopPropagation();
},
////////////////
// Client-Server
setHasShowListener : function( value ) {
if( !this.hasState( "rwt_BAR" ) ) {
this._hasShowListener = value;
}
},
setHasHideListener : function( value ) {
if( !this.hasState( "rwt_BAR" ) ) {
this._hasHideListener = value;
}
},
_menuShown : function() {
if( !rwt.remote.EventUtil.getSuspended() ) {
if( this._hasShowListener ) {
// create preliminary item
if( this._preItem == null ) {
this._preItem = new rwt.widgets.MenuItem( "push" );
this._preItem.setText( "..." );
this._preItem.setEnabled( false );
this.addMenuItemAt( this._preItem, 0 );
}
// hide all but the preliminary item
var items = this._layout.getChildren();
for( var i = 0; i < items.length; i++ ) {
var item = items[ i ];
item.setDisplay( false );
}
this._preItem.setDisplay( true );
this._itemsHiddenFlag = true;
if( this.getWidth() < 60 ) {
this.setWidth( 60 );
}
//this.setDisplay( true ); //wouldn't be called if display was false
// send event
rwt.remote.Server.getInstance().getRemoteObject( this ).notify( "Show" );
} else {
var display = this._layout.getChildren().length !== 0;
//no items and no listener to add some:
this.setDisplay( display );
if( display ) {
if( this._hoverFirstItemFlag ) {
this.hoverFirstItem();
}
}
}
}
},
_menuHidden : function() {
if( !rwt.remote.EventUtil.getSuspended() ) {
if( this._hasHideListener ) {
rwt.remote.Server.getInstance().getRemoteObject( this ).notify( "Hide" );
}
}
},
unhideItems : function( reveal ) {
if( reveal ) {
var items = this._layout.getChildren();
for( var i = 0; i < items.length; i++ ) {
items[ i ].setDisplay( true );
}
if( this._preItem ) {
this._preItem.setDisplay( false );
}
this._itemsHiddenFlag = false;
if( this._hoverFirstItemFlag ) {
this.hoverFirstItem();
}
} else {
this.hide();
}
this._hoverFirstItemFlag = false;
},
// Called to open a popup menu from server side
showMenu : function( menu, x, y ) {
if( menu != null ) {
menu._renderAppearance();
menu.setLocation( x, y );
menu.show();
}
}
}
} );