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.event.EventHandler.js Maven / Gradle / Ivy
Go to download
The Rich Ajax Platform lets you build rich, Ajax-enabled Web applications.
/*******************************************************************************
* Copyright: 2004, 2012 1&1 Internet AG, Germany, http://www.1und1.de,
* and EclipseSource
*
* 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:
* 1&1 Internet AG and others - original API and implementation
* EclipseSource - adaptation for the Eclipse Rich Ajax Platform
******************************************************************************/
rwt.qx.Class.define( "rwt.event.EventHandler", {
type : "static",
statics : {
_filter : {},
_allowContextMenu : rwt.util.Functions.returnFalse,
_captureWidget : null,
_focusRoot : null,
_menuManager : null,
// state storage:
_focused : false,
_lastMouseEventType : null,
_lastMouseDown : false,
_lastMouseEventDate : 0,
_mouseIsDown : false,
///////////////////
// Public functions
init : function() {
var functionUtil = rwt.util.Functions;
this.__onmouseevent = functionUtil.bind( this._onmouseevent, this );
this.__ondragevent = functionUtil.bind( this._ondragevent, this );
this.__onselectevent = functionUtil.bind( this._onselectevent, this );
this.__onwindowblur = functionUtil.bind( this._onwindowblur, this );
this.__onwindowfocus = functionUtil.bind( this._onwindowfocus, this );
this.__onwindowresize = functionUtil.bind( this._onwindowresize, this );
this.__onKeyEvent = rwt.util.Functions.bind( this._onKeyEvent, this );
rwt.event.EventHandlerUtil.applyBrowserFixes();
},
cleanUp : function() {
delete this.__onmouseevent;
delete this.__ondragevent;
delete this.__onselectevent;
delete this.__onwindowblur;
delete this.__onwindowfocus;
delete this.__onwindowresize;
delete this.__onKeyEvent;
delete this._lastMouseEventType;
delete this._lastMouseDown;
delete this._lastMouseEventDate;
delete this._lastMouseDownDomTarget;
delete this._lastMouseDownDispatchTarget;
rwt.event.EventHandlerUtil.cleanUp();
},
attachEvents : function() {
var eventUtil = rwt.html.EventRegistration;
this.attachEventTypes( this._mouseEventTypes, this.__onmouseevent );
this.attachEventTypes( this._dragEventTypes, this.__ondragevent );
this.attachEventTypes( this._keyEventTypes, this.__onKeyEvent );
eventUtil.addEventListener( window, "blur", this.__onwindowblur );
eventUtil.addEventListener( window, "focus", this.__onwindowfocus );
eventUtil.addEventListener( window, "resize", this.__onwindowresize );
document.body.onselect = this.__onselectevent;
document.onselectstart = this.__onselectevent;
document.onselectionchange = this.__onselectevent;
},
detachEvents : function() {
var eventUtil = rwt.html.EventRegistration;
this.detachEventTypes( this._mouseEventTypes, this.__onmouseevent);
this.detachEventTypes( this._dragEventTypes, this.__ondragevent);
this.detachEventTypes( this._keyEventTypes, this.__onKeyEvent );
eventUtil.removeEventListener( window, "blur", this.__onwindowblur );
eventUtil.removeEventListener( window, "focus", this.__onwindowfocus );
eventUtil.removeEventListener( window, "resize", this.__onwindowresize );
document.body.onselect = null;
document.onselectstart = null;
document.onselectionchange = null;
},
setCaptureWidget : function( widget ) {
if( this._captureWidget !== widget ) {
if( this._captureWidget !== null ) {
this._captureWidget.setCapture( false );
}
this._captureWidget = widget;
if( widget != null ) {
widget.setCapture( true );
}
}
},
getCaptureWidget : function() {
return this._captureWidget;
},
setFocusRoot : function( widget ) {
if( widget !== this._focusRoot ) {
if( this._focusRoot !== null ) {
this._focusRoot.setFocusedChild( null );
}
this._focusRoot = widget;
if( widget !== null && widget.getFocusedChild() === null ) {
widget.setFocusedChild( widget );
}
}
},
getFocusRoot : function() {
return this._focusRoot;
},
/**
* Sets a callback-function to decide if the native context-
* menu is displayed. It will be called on DOM-events of the type
* "contextmenu". The target-Widget of the event will be given as
* the first argument, the dom-target as the second.
* It must return a boolean. Null is not allowed.
*
*/
setAllowContextMenu : function( func ) {
this._allowContextMenu = func;
},
setMenuManager : function( manager ) {
this._menuManager = manager;
},
getMenuManager : function( manager ) {
return this._menuManager;
},
setMouseEventFilter : function( filter, context ) {
this._filter[ "mouseevent" ] = [ filter, context ];
},
setKeyEventFilter : function( filter, context ) {
// TODO [tb] : Unify behavior and API for EventFilter, only use event
// wrapper objects instead of dom-events, create API for order of filter
this._filter[ "keyevent" ] = [ filter, context ];
},
setKeyDomEventFilter : function( filter, context ) {
this._filter[ "domKeyevent" ] = [ filter, context ];
},
//////////////
// KEY EVENTS:
_onKeyEvent : function() {
try {
var EventHandlerUtil = rwt.event.EventHandlerUtil;
var event = EventHandlerUtil.getDomEvent( arguments );
var keyCode = EventHandlerUtil.getKeyCode( event );
var charCode = EventHandlerUtil.getCharCode( event );
if( typeof this._filter[ "domKeyevent" ] !== "undefined" ) {
var context = this._filter[ "domKeyevent" ][ 1 ];
var func = this._filter[ "domKeyevent" ][ 0 ];
func.call( context, event.type, keyCode, charCode, event );
}
var pseudoTypes = EventHandlerUtil.getEventPseudoTypes( event, keyCode, charCode );
var keyUpCodes = EventHandlerUtil.mustRestoreKeyup( keyCode, pseudoTypes );
for( var i = 0; i < keyUpCodes.length; i++ ) {
this._onkeyevent_post( event, "keyup", keyUpCodes[ i ], 0 );
EventHandlerUtil.clearStuckKey( keyUpCodes[ i ] );
}
for( var i = 0; i < pseudoTypes.length; i++ ) {
this._onkeyevent_post( event, pseudoTypes[ i ], keyCode, charCode );
}
if( EventHandlerUtil.mustRestoreKeypress( event, pseudoTypes ) ) {
this._onkeyevent_post( event, "keypress", keyCode, charCode );
}
EventHandlerUtil.saveData( event, keyCode, charCode );
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
_onkeyevent_post : function( vDomEvent, vType, vKeyCode, vCharCode ) {
var process = true;
if( typeof this._filter[ "keyevent" ] !== "undefined" ) {
var context = this._filter[ "keyevent" ][ 1 ];
var func = this._filter[ "keyevent" ][ 0 ];
process = func.call( context, vType, vKeyCode, vCharCode, vDomEvent );
}
if( process ) {
this._processKeyEvent( vDomEvent, vType, vKeyCode, vCharCode );
}
},
_processKeyEvent : function( vDomEvent, vType, vKeyCode, vCharCode ) {
var EventHandlerUtil = rwt.event.EventHandlerUtil;
var keyIdentifier;
if( !isNaN( vKeyCode ) && vKeyCode !== 0 ) {
keyIdentifier = EventHandlerUtil.keyCodeToIdentifier( vKeyCode );
} else {
keyIdentifier = EventHandlerUtil.charCodeToIdentifier( vCharCode );
}
var vDomTarget = EventHandlerUtil.getDomTarget( vDomEvent );
var vTarget = this._getKeyEventTarget();
var vKeyEventObject = new rwt.event.KeyEvent( vType,
vDomEvent,
vDomTarget,
vTarget,
null,
vKeyCode,
vCharCode,
keyIdentifier );
if( vTarget != null && vTarget.getEnabled() ) {
switch( keyIdentifier ) {
case "Escape":
case "Tab":
if ( this._menuManager != null ) {
this._menuManager.update(vTarget, vType);
}
break;
}
if( vDomEvent.ctrlKey && keyIdentifier == "A" ) {
switch( vDomTarget.tagName.toLowerCase() ) {
case "input":
case "textarea":
case "iframe":
// selection allowed
break;
default:
EventHandlerUtil.stopDomEvent(vDomEvent);
break;
}
}
vTarget.dispatchEvent( vKeyEventObject );
if( rwt.qx.Class.isDefined("rwt.event.DragAndDropHandler") ) {
rwt.event.DragAndDropHandler.getInstance().handleKeyEvent( vKeyEventObject );
}
}
vKeyEventObject.dispose();
},
///////////////
// MOUSE EVENTS
_onmouseevent : function( event ) {
try {
var process = true;
if( typeof this._filter[ "mouseevent" ] !== "undefined" ) {
var context = this._filter[ "mouseevent" ][ 1 ];
process = this._filter[ "mouseevent" ][ 0 ].call( context, event );
}
if( process ) {
this._processMouseEvent( event );
}
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
// TODO [tb] : refactor to work like _onKeyEvent
_processMouseEvent : rwt.util.Variant.select("qx.client", {
"mshtml" : function() {
var EventHandlerUtil = rwt.event.EventHandlerUtil;
var vDomEvent = EventHandlerUtil.getDomEvent( arguments );
var vDomTarget = EventHandlerUtil.getDomTarget( vDomEvent );
var vType = vDomEvent.type;
if( vType == "mousemove" ) {
if( this._mouseIsDown && vDomEvent.button === 0 ) {
this._onmouseevent_post( vDomEvent, "mouseup", vDomTarget );
this._mouseIsDown = false;
}
} else {
if( vType == "mousedown" ) {
this._mouseIsDown = true;
} else if( vType == "mouseup" ) {
this._mouseIsDown = false;
}
if( vType == "mouseup"
&& !this._lastMouseDown
&& ( ( new Date() ).valueOf() - this._lastMouseEventDate ) < 250
) {
// Fix MSHTML Mouseup, should be after a normal click
// or contextmenu event, like Mozilla does this
this._onmouseevent_post( vDomEvent, "mousedown", vDomTarget );
} else if ( vType == "dblclick"
&& this._lastMouseEventType == "mouseup"
&& ( ( new Date() ).valueOf() - this._lastMouseEventDate ) < 250
) {
// Fix MSHTML Doubleclick, should be after a normal click event,
// like Mozilla does this
this._onmouseevent_post(vDomEvent, "click", vDomTarget);
}
switch( vType ) {
case "mousedown":
case "mouseup":
case "click":
case "dblclick":
case "contextmenu":
this._lastMouseEventType = vType;
this._lastMouseEventDate = ( new Date() ).valueOf();
this._lastMouseDown = vType == "mousedown";
break;
}
}
this._onmouseevent_post(vDomEvent, vType, vDomTarget);
},
"default" : function( vDomEvent ) {
var EventHandlerUtil = rwt.event.EventHandlerUtil;
var vDomTarget = EventHandlerUtil.getDomTarget( vDomEvent );
var vType = vDomEvent.type;
switch(vType) {
case "DOMMouseScroll":
vType = "mousewheel";
break;
case "click":
case "dblclick":
// ignore click or dblclick events with other then the left mouse button
if( vDomEvent.which !== 1 ) {
return;
}
}
this._onmouseevent_post( vDomEvent, vType, vDomTarget );
}
} ),
_onmouseevent_post : function( vDomEvent, vType, vDomTarget ) {
var eventConsumed = false;
var EventHandlerUtil = rwt.event.EventHandlerUtil;
var vCaptureTarget = this.getCaptureWidget();
var vOriginalTarget = EventHandlerUtil.getOriginalTargetObject( vDomTarget );
var vTarget = EventHandlerUtil.getTargetObject( null, vOriginalTarget, true );
if( !vTarget ) {
return;
}
var vDispatchTarget = vCaptureTarget ? vCaptureTarget : vTarget;
var vFixClick = this._onmouseevent_click_fix( vDomTarget, vType, vDispatchTarget );
if( vType == "contextmenu" ) {
if( this._allowContextMenu( vOriginalTarget, vDomTarget ) ) {
eventConsumed = true;
} else {
EventHandlerUtil.stopDomEvent( vDomEvent );
}
}
if( vDispatchTarget.getEnabled()
&& !( vDispatchTarget instanceof rwt.widgets.base.ClientDocument )
&& vType == "mousedown" ) {
rwt.widgets.util.FocusHandler.mouseFocus = true;
var vRoot = vDispatchTarget.getFocusRoot();
if( vRoot ) {
this.setFocusRoot( vRoot );
var vFocusTarget = vDispatchTarget;
while( !vFocusTarget.isFocusable() && vFocusTarget != vRoot ) {
vFocusTarget = vFocusTarget.getParent();
}
// We need to focus first and active afterwards.
// Otherwise the focus will activate another widget if the
// active one is not tabable.
vRoot.setFocusedChild( vFocusTarget );
vRoot.setActiveChild( vDispatchTarget );
}
}
// handle related target object
if( vType == "mouseover" || vType == "mouseout" ) {
var vRelatedTarget = EventHandlerUtil.getRelatedTargetObjectFromEvent( vDomEvent );
var elementEventType = vType == "mouseover" ? "elementOver" : "elementOut";
this._fireElementHoverEvents( elementEventType,
vDomEvent,
vDomTarget,
vTarget,
vOriginalTarget,
vRelatedTarget,
vDispatchTarget );
// Ignore events where the related target and
// the real target are equal - from our sight
if( vRelatedTarget == vTarget ) {
return;
}
}
var vEventObject = new rwt.event.MouseEvent( vType,
vDomEvent,
vDomTarget,
vTarget,
vOriginalTarget,
vRelatedTarget );
// Store last Event in MouseEvent Constructor. Needed for Tooltips, ...
if( vType !== "contextmenu" ) {
rwt.event.MouseEvent.storeEventState( vEventObject );
}
if( !eventConsumed ) {
vDispatchTarget.dispatchEvent( vEventObject );
if( vDispatchTarget.getEnabled() ) {
this._onmouseevent_special_post( vType,
vTarget,
vOriginalTarget,
vDispatchTarget,
vEventObject,
vDomEvent );
}
} else if( vType == "mouseover" ) {
var toolTipManager = rwt.widgets.util.ToolTipManager.getInstance();
toolTipManager.handleMouseEvent( vEventObject );
}
vEventObject.dispose();
rwt.widgets.base.Widget.flushGlobalQueues();
// Fix Click (Gecko Bug, see above)
if( vFixClick ) {
this._onmouseevent_post( vDomEvent, "click", this._lastMouseDownDomTarget );
this._lastMouseDownDomTarget = null;
this._lastMouseDownDispatchTarget = null;
}
},
_fireElementHoverEvents : function( type,
domEvent,
domTarget,
target,
originalTarget,
relatedTarget,
dispatchTarget )
{
if( dispatchTarget.getEnabled() ) {
var eventObject = new rwt.event.MouseEvent( type,
domEvent,
domTarget,
target,
originalTarget,
relatedTarget );
dispatchTarget.dispatchEvent( eventObject );
}
},
_onmouseevent_special_post : function( vType,
vTarget,
vOriginalTarget,
vDispatchTarget,
vEventObject,
vDomEvent )
{
switch( vType ) {
case "mousedown":
rwt.widgets.util.PopupManager.getInstance().update( vTarget );
if( this._menuManager != null ) {
this._menuManager.update( vTarget, vType );
}
rwt.widgets.util.IframeManager.getInstance().handleMouseDown( vEventObject );
break;
case "mouseup":
// Mouseup event should always hide, independed of target,
// so don't send a target
if( this._menuManager != null ) {
this._menuManager.update( vTarget, vType );
}
if( rwt.qx.Class.isDefined("rwt.widgets.util.IframeManager" ) ) {
rwt.widgets.util.IframeManager.getInstance().handleMouseUp( vEventObject );
}
break;
}
rwt.widgets.util.ToolTipManager.getInstance().handleMouseEvent( vEventObject );
this._ignoreWindowBlur = vType === "mousedown";
if( rwt.qx.Class.isDefined("rwt.event.DragAndDropHandler" ) && vTarget ) {
rwt.event.DragAndDropHandler.getInstance().handleMouseEvent( vEventObject );
}
},
_ondragevent : function( vEvent ) {
try {
var EventHandlerUtil = rwt.event.EventHandlerUtil;
if( !vEvent ) {
vEvent = window.event;
}
EventHandlerUtil.stopDomEvent( vEvent );
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
////////////////
// SELECT EVENTS
_onselectevent : function( ) {
try {
var EventHandlerUtil = rwt.event.EventHandlerUtil;
var e = EventHandlerUtil.getDomEvent( arguments );
var target = EventHandlerUtil.getOriginalTargetObjectFromEvent( e );
while( target ) {
if( target.getSelectable() != null ) {
if ( !target.getSelectable() ) {
EventHandlerUtil.stopDomEvent( e );
}
break;
}
target = target.getParent();
}
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
_onwindowblur : function( e ) {
try {
if ( !this._focused || this._ignoreWindowBlur || e.originalTarget != window ) {
return;
}
this._focused = false;
this.setCaptureWidget( null );
if( rwt.qx.Class.isDefined( "rwt.widgets.util.PopupManager" ) ) {
rwt.widgets.util.PopupManager.getInstance().update();
}
if ( this._menuManager ) {
this._menuManager.update();
}
if( rwt.qx.Class.isDefined( "rwt.event.DragAndDropHandler" ) ) {
rwt.event.DragAndDropHandler.getInstance().globalCancelDrag();
}
rwt.widgets.base.ClientDocument.getInstance().createDispatchEvent( "windowblur" );
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
_onwindowfocus : function( e ) {
try {
if( this._focused ) {
return;
}
this._focused = true;
rwt.widgets.base.ClientDocument.getInstance().createDispatchEvent( "windowfocus" );
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
_onwindowresize : function( e ) {
try {
var clientDocument = rwt.widgets.base.ClientDocument.getInstance();
// Catch redundant resize events, fired for example by iPad:
var oldWidth = clientDocument.getInnerWidth();
var oldHeight = clientDocument.getInnerHeight();
var width = clientDocument._computeInnerWidth();
var height = clientDocument._computeInnerHeight();
if( width !== oldWidth || height !== oldHeight ) {
rwt.widgets.base.ClientDocument.getInstance().createDispatchEvent( "windowresize" );
}
} catch( ex ) {
rwt.runtime.ErrorHandler.processJavaScriptError( ex );
}
},
///////////////
// Helper-maps:
_mouseEventTypes : [
"mouseover",
"mousemove",
"mouseout",
"mousedown",
"mouseup",
"click",
"dblclick",
"contextmenu",
rwt.client.Client.isGecko() ? "DOMMouseScroll" : "mousewheel"
],
_keyEventTypes : [
"keydown",
"keypress",
"keyup"
],
_dragEventTypes : rwt.util.Variant.select("qx.client", {
"gecko" : [
"dragdrop",
"dragover",
"dragenter",
"dragexit",
"draggesture"
],
"mshtml" : [
"dragend",
"dragover",
"dragstart",
"drag",
"dragenter",
"dragleave"
],
"default" : [
"dragstart",
"dragdrop",
"dragover",
"drag",
"dragleave",
"dragenter",
"dragexit",
"draggesture"
]
} ),
////////////////////
// Helper-functions:
_getKeyEventTarget : function() {
var vFocusRoot = this.getFocusRoot();
return this.getCaptureWidget() || ( vFocusRoot == null ? null : vFocusRoot.getActiveChild() );
},
attachEventTypes : function( vEventTypes, vFunctionPointer ) {
try {
// Gecko is a bit buggy to handle key events on document if
// not previously focused. Internet Explorer has problems to use
// 'window', so there we use the 'body' element
var el = rwt.client.Client.isGecko() ? window : document.body;
for( var i=0, l=vEventTypes.length; i