@qooxdoo/framework
Version:
The JS Framework for Coders
393 lines (309 loc) • 9.62 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Sebastian Werner (wpbasti)
* Fabian Jakobs (fjakobs)
************************************************************************ */
/**
* Connects the widgets to the browser DOM events.
*/
qx.Class.define("qx.ui.core.EventHandler",
{
extend : qx.core.Object,
implement : qx.event.IEventHandler,
/*
*****************************************************************************
CONSTRUCTOR
*****************************************************************************
*/
construct : function()
{
this.base(arguments);
this.__manager = qx.event.Registration.getManager(window);
},
/*
*****************************************************************************
STATICS
*****************************************************************************
*/
statics :
{
/** @type {Integer} Priority of this handler */
PRIORITY : qx.event.Registration.PRIORITY_FIRST,
/** @type {Map} Supported event types. Identical to events map of qx.ui.core.Widget */
SUPPORTED_TYPES :
{
// mouse events
mousemove : 1,
mouseover : 1,
mouseout : 1,
mousedown : 1,
mouseup : 1,
click : 1,
auxclick : 1,
dblclick : 1,
contextmenu : 1,
mousewheel : 1,
// key events
keyup : 1,
keydown : 1,
keypress : 1,
keyinput : 1,
// mouse capture
capture : 1,
losecapture : 1,
// focus events
focusin : 1,
focusout : 1,
focus : 1,
blur : 1,
activate : 1,
deactivate : 1,
// appear events
appear : 1,
disappear : 1,
// drag drop events
dragstart : 1,
dragend : 1,
dragover : 1,
dragleave : 1,
drop : 1,
drag : 1,
dragchange : 1,
droprequest : 1,
// touch events
touchstart : 1,
touchend : 1,
touchmove : 1,
touchcancel : 1,
// gestures
tap : 1,
longtap : 1,
swipe : 1,
dbltap : 1,
track : 1,
trackend : 1,
trackstart : 1,
pinch : 1,
rotate : 1,
roll : 1,
// pointer events
pointermove : 1,
pointerover : 1,
pointerout : 1,
pointerdown : 1,
pointerup : 1,
pointercancel : 1
},
/** @type {Integer} Whether the method "canHandleEvent" must be called */
IGNORE_CAN_HANDLE : false
},
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members :
{
__manager : null,
/**
* @type {Map} Supported focus event types
*
* @lint ignoreReferenceField(__focusEvents)
*/
__focusEvents :
{
focusin : 1,
focusout : 1,
focus : 1,
blur : 1
},
/**
* @type {Map} Map of events which should be fired independently from being disabled
*
* @lint ignoreReferenceField(__ignoreDisabled)
*/
__ignoreDisabled :
{
// mouse events
mouseover : 1,
mouseout : 1,
// appear events
appear : 1,
disappear : 1
},
// interface implementation
canHandleEvent : function(target, type) {
return target instanceof qx.ui.core.Widget;
},
/**
* Dispatches a DOM event on a widget.
*
* @param domEvent {qx.event.type.Event} The event object to dispatch.
*/
_dispatchEvent : function(domEvent)
{
// EVENT TARGET
var domTarget = domEvent.getTarget();
var widgetTarget = qx.ui.core.Widget.getWidgetByElement(domTarget);
var targetChanged = false;
while (widgetTarget && widgetTarget.isAnonymous())
{
var targetChanged = true;
widgetTarget = widgetTarget.getLayoutParent();
}
// don't activate anonymous widgets!
if (widgetTarget && targetChanged && domEvent.getType() == "activate") {
widgetTarget.getContentElement().activate();
}
// Correcting target for focus events
if (this.__focusEvents[domEvent.getType()])
{
widgetTarget = widgetTarget && widgetTarget.getFocusTarget();
// Whether nothing is returned
if (!widgetTarget) {
return;
}
}
// EVENT RELATED TARGET
if (domEvent.getRelatedTarget)
{
var domRelatedTarget = domEvent.getRelatedTarget();
var widgetRelatedTarget = qx.ui.core.Widget.getWidgetByElement(domRelatedTarget);
while (widgetRelatedTarget && widgetRelatedTarget.isAnonymous()) {
widgetRelatedTarget = widgetRelatedTarget.getLayoutParent();
}
if (widgetRelatedTarget)
{
// Correcting target for focus events
if (this.__focusEvents[domEvent.getType()]) {
widgetRelatedTarget = widgetRelatedTarget.getFocusTarget();
}
// If target and related target are identical ignore the event
if (widgetRelatedTarget === widgetTarget) {
return;
}
}
}
// EVENT CURRENT TARGET
var currentTarget = domEvent.getCurrentTarget();
var currentWidget = qx.ui.core.Widget.getWidgetByElement(currentTarget);
if (!currentWidget || currentWidget.isAnonymous()) {
return;
}
// Correcting target for focus events
if (this.__focusEvents[domEvent.getType()]) {
currentWidget = currentWidget.getFocusTarget();
}
// Ignore most events in the disabled state.
var type = domEvent.getType();
if (!currentWidget || !(currentWidget.isEnabled() || this.__ignoreDisabled[type])) {
return;
}
// PROCESS LISTENERS
// Load listeners
var capture = domEvent.getEventPhase() == qx.event.type.Event.CAPTURING_PHASE;
var listeners = this.__manager.getListeners(currentWidget, type, capture);
if (domEvent.getEventPhase() == qx.event.type.Event.AT_TARGET) {
if (!listeners) {
listeners = [];
}
var otherListeners = this.__manager.getListeners(currentWidget, type, !capture);
if (otherListeners) {
listeners = listeners.concat(otherListeners);
}
}
if (!listeners || listeners.length === 0) {
return;
}
// Create cloned event with correct target
var widgetEvent = qx.event.Pool.getInstance().getObject(domEvent.constructor);
domEvent.clone(widgetEvent);
widgetEvent.setTarget(widgetTarget);
widgetEvent.setRelatedTarget(widgetRelatedTarget||null);
widgetEvent.setCurrentTarget(currentWidget);
// Keep original target of DOM event, otherwise map it to the original
var orig = domEvent.getOriginalTarget();
if (orig)
{
var widgetOriginalTarget = qx.ui.core.Widget.getWidgetByElement(orig);
while (widgetOriginalTarget && widgetOriginalTarget.isAnonymous()) {
widgetOriginalTarget = widgetOriginalTarget.getLayoutParent();
}
widgetEvent.setOriginalTarget(widgetOriginalTarget);
}
else
{
widgetEvent.setOriginalTarget(domTarget);
}
// Dispatch it on all listeners
var tracker = {};
qx.event.Utils.then(tracker, function() {
return qx.event.Utils.series(listeners, function(listener) {
var context = listener.context || currentWidget;
return listener.handler.call(context, widgetEvent);
});
});
// Synchronize propagation stopped/prevent default property
qx.event.Utils.then(tracker, function() {
if (widgetEvent.getPropagationStopped()) {
domEvent.stopPropagation();
}
if (widgetEvent.getDefaultPrevented()) {
domEvent.preventDefault();
}
});
return qx.event.Utils.then(tracker, function() {
qx.event.Pool.getInstance().poolObject(widgetEvent);
});
},
// interface implementation
registerEvent : function(target, type, capture)
{
var elem;
if (type === "focus" || type === "blur") {
elem = target.getFocusElement();
} else {
elem = target.getContentElement();
}
if (elem) {
elem.addListener(type, this._dispatchEvent, this, capture);
}
},
// interface implementation
unregisterEvent : function(target, type, capture)
{
var elem;
if (type === "focus" || type === "blur") {
elem = target.getFocusElement();
} else {
elem = target.getContentElement();
}
if (elem) {
elem.removeListener(type, this._dispatchEvent, this, capture);
}
}
},
/*
*****************************************************************************
DESTRUCTOR
*****************************************************************************
*/
destruct : function() {
this.__manager = null;
},
/*
*****************************************************************************
DEFER
*****************************************************************************
*/
defer : function(statics) {
qx.event.Registration.addHandler(statics);
}
});