@qooxdoo/framework
Version:
The JS Framework for Coders
1,065 lines (928 loc) • 33.6 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2007-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:
* Fabian Jakobs (fjakobs)
* Sebastian Werner (wpbasti)
* John Spackman (johnspackman)
* Christian Boulanger (cboulanger)
************************************************************************ */
/**
* Wrapper for browser DOM event handling for each browser window/frame.
*
* @require(qx.bom.Event)
*/
qx.Class.define("qx.event.Manager", {
extend: Object,
implement: [qx.core.IDisposable],
/*
*****************************************************************************
CONSTRUCTOR
*****************************************************************************
*/
/**
* Creates a new instance of the event handler.
*
* @param win {Window} The DOM window this manager handles the events for
* @param registration {qx.event.Registration} The event registration to use
*/
construct(win, registration) {
// Assign window object
this.__window = win;
this.__windowId = qx.core.ObjectRegistry.toHashCode(win);
this.__registration = registration;
// Register to the page unload event.
// Only for iframes and other secondary documents.
if (win.qx !== qx) {
var self = this;
var method = function () {
qx.bom.Event.removeNativeListener(win, "unload", method);
self.dispose();
};
if (qx.core.Environment.get("qx.globalErrorHandling")) {
qx.bom.Event.addNativeListener(
win,
"unload",
qx.event.GlobalError.observeMethod(method)
);
} else {
qx.bom.Event.addNativeListener(win, "unload", method);
}
}
// Registry for event listeners
this.__listeners = new Map();
// The handler and dispatcher instances
this.__handlers = {};
this.__dispatchers = {};
this.__handlerCache = {};
this.__clearBlackList = new qx.util.DeferredCall(function () {
this.__blacklist = null;
}, this);
this.__clearBlackList.$$blackListCleaner = true;
},
/*
*****************************************************************************
STATICS
*****************************************************************************
*/
statics: {
/** @type {Integer} Last used ID for an event */
__lastUnique: 0,
/**
* Returns an unique ID which may be used in combination with a target and
* a type to identify an event entry.
*
* @return {String} The next free identifier (auto-incremented)
*/
getNextUniqueId() {
return this.__lastUnique++ + "";
},
/**
* @type {Array} private list of global event monitor functions
*/
__globalEventMonitors: [],
/**
* Adds a global event monitor function which is called for each event fired
* anywhere in the application. The function is called with the signature
* (target: {@link qx.core.Object}, event: {@link qx.event.type.Event}).
* Since for performance reasons, the original event object is passed,
* the monitor function must not change this event in any way.
*
* @param fn {Function} Monitor function
* @param context {Object?} Optional execution context of the function
*/
addGlobalEventMonitor(fn, context) {
qx.core.Assert.assertFunction(fn);
fn.$$context = context;
this.__globalEventMonitors.push(fn);
},
/**
* Removes a global event monitor function that had
* previously been added.
* @param fn {Function} The global monitor function
*/
removeGlobalEventMonitor(fn) {
qx.core.Assert.assertFunction(fn);
qx.lang.Array.remove(this.__globalEventMonitors, fn);
},
/**
* Remove all registered event monitors
*/
resetGlobalEventMonitors() {
qx.event.Manager.__globalEventMonitors = [];
},
/**
* Returns the global event monitor. Not compatible with the {@link
* qx.event.Manager.addGlobalEventMonitor} API. Will be removed in v7.0.0
*
* @deprecated {6.0}
* @return {Function?} the global monitor function
*/
getGlobalEventMonitor() {
return this.__globalEventMonitors[0];
},
/**
* Sets the global event monitor. Not compatible with the {@link
* qx.event.Manager.addGlobalEventMonitor} API. Will be removed in
* v7.0.0. Use {@link qx.event.Manager.addGlobalEventMonitor} instead.
*
* @deprecated {6.0}
* @param fn {Function?} the global monitor function
*/
setGlobalEventMonitor(fn) {
qx.core.Assert.assertFunction(fn);
this.__globalEventMonitors[0] = fn;
}
},
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members: {
__registration: null,
__listeners: null,
__dispatchers: null,
__disposeWrapper: null,
__handlers: null,
__handlerCache: null,
__window: null,
__windowId: null,
__blacklist: null,
__clearBlackList: null,
/*
---------------------------------------------------------------------------
HELPERS
---------------------------------------------------------------------------
*/
/**
* Get the window instance the event manager is responsible for
*
* @return {Window} DOM window instance
*/
getWindow() {
return this.__window;
},
/**
* Get the hashcode of the manager's window
*
* @return {String} The window's hashcode
*/
getWindowId() {
return this.__windowId;
},
/**
* Returns an instance of the given handler class for this manager(window).
*
* @param clazz {Class} Any class which implements {@link qx.event.IEventHandler}
* @return {Object} The instance used by this manager
*/
getHandler(clazz) {
var handler = this.__handlers[clazz.classname];
if (handler) {
return handler;
}
return (this.__handlers[clazz.classname] = new clazz(this));
},
/**
* Returns an instance of the given dispatcher class for this manager(window).
*
* @param clazz {Class} Any class which implements {@link qx.event.IEventHandler}
* @return {Object} The instance used by this manager
*/
getDispatcher(clazz) {
var dispatcher = this.__dispatchers[clazz.classname];
if (dispatcher) {
return dispatcher;
}
return (this.__dispatchers[clazz.classname] = new clazz(
this,
this.__registration
));
},
/*
---------------------------------------------------------------------------
EVENT LISTENER MANAGEMENT
---------------------------------------------------------------------------
*/
/**
* Get a copy of all event listeners for the given combination
* of target, event type and phase.
*
* This method is especially useful and for event handlers to
* to query the listeners registered in the manager.
*
* @param target {Object} Any valid event target
* @param type {String} Event type
* @param capture {Boolean ? false} Whether the listener is for the
* capturing phase of the bubbling phase.
* @return {Array|null} Array of registered event handlers. May return
* null when no listener were found.
*/
getListeners(target, type, capture) {
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
return null;
}
var entryKey = type + (capture ? "|capture" : "|bubble");
var entryMap = targetMap.get(entryKey);
if (entryMap && entryMap.size > 0) {
var listeners = [...entryMap.values()];
return new Proxy(listeners, {
deleteProperty(target, property) {
if (property !== "length") {
var listener = target[property];
entryMap.delete(listener.unique);
}
delete target[property];
return true;
},
set(target, property, value, receiver) {
if (property !== "length") {
if (!value.unique) {
throw new Error("Cannot store a listener without a unique id. Use addListener()");
}
entryMap[value.unique] = value;
}
target[property] = value;
return true;
}
});
}
return null;
},
/**
* Returns all registered listeners.
*
* @internal
*
* @return {Object} All registered listeners. The key is the hash code for an object.
*/
getAllListeners() {
return Object.fromEntries(
this.__listeners.entries().map(
([targetKey, targetMap]) => [targetKey, Object.fromEntries(
targetMap.entries().map(
([entryKey, entryMap]) => {
var listeners = [...entryMap.values()];
var proxy = new Proxy(listeners, {
deleteProperty(target, property) {
if (property !== "length") {
var listener = target[property];
entryMap.delete(listener.unique);
}
delete target[property];
return true;
},
set(target, property, value, receiver) {
if (property !== "length") {
if (!value.unique) {
throw new Error("Cannot store a listener without a unique id. Use addListener()");
}
entryMap[value.unique] = value;
}
target[property] = value;
return true;
}
})
return [entryKey, proxy];
}
)
)]
)
);
},
/**
* Returns a serialized array of all events attached on the given target.
*
* @param target {Object} Any valid event target
* @return {Map[]} Array of maps where everyone contains the keys:
* <code>handler</code>, <code>self</code>, <code>type</code> and <code>capture</code>.
*/
serializeListeners(target) {
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
var result = [];
if (targetMap) {
var indexOf, type, capture;
for (const [entryKey, entryMap] of targetMap) {
indexOf = entryKey.indexOf("|");
type = entryKey.substring(0, indexOf);
capture = entryKey.charAt(indexOf + 1) === "c";
result = result.concat(
[...entryMap.values().map(entry => ({
self: entry.context,
handler: entry.handler,
type: type,
capture: capture
})
)]
);
}
}
return result;
},
/**
* This method might be used to temporally remove all events
* directly attached to the given target. This do not work
* have any effect on bubbling events normally.
*
* This is mainly thought for detaching events in IE, before
* cloning them. It also removes all leak scenarios
* when unloading a document and may be used here as well.
*
* @internal
* @param target {Object} Any valid event target
* @param enable {Boolean} Whether to enable or disable the events
*/
toggleAttachedEvents(target, enable) {
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (targetMap) {
var indexOf, type, capture;
for (const entryKey of targetMap.keys()) {
indexOf = entryKey.indexOf("|");
type = entryKey.substring(0, indexOf);
capture = entryKey.charCodeAt(indexOf + 1) === 99; // checking for character "c".
if (enable) {
this.__registerAtHandler(target, type, capture);
} else {
this.__unregisterAtHandler(target, type, capture);
}
}
}
},
/**
* Check whether there are one or more listeners for an event type
* registered at the target.
*
* @param target {Object} Any valid event target
* @param type {String} The event type
* @param capture {Boolean ? false} Whether to check for listeners of
* the bubbling or of the capturing phase.
* @return {Boolean} Whether the target has event listeners of the given type.
*/
hasListener(target, type, capture) {
if (qx.core.Environment.get("qx.debug")) {
if (target == null) {
qx.log.Logger.trace(this);
throw new Error("Invalid object: " + target);
}
}
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
return false;
}
var entryKey = type + (capture ? "|capture" : "|bubble");
var entryMap = targetMap.get(entryKey);
return Boolean(entryMap && entryMap.size > 0);
},
/**
* Imports a list of event listeners at once. This only
* works for newly created elements as it replaces
* all existing data structures.
*
* Works with a map of data. Each entry in this map should be a
* map again with the keys <code>type</code>, <code>listener</code>,
* <code>self</code>, <code>capture</code> and an optional <code>unique</code>.
*
* The values are identical to the parameters of {@link #addListener}.
* For details please have a look there.
*
* @param target {Object} Any valid event target
* @param list {Map} A map where every listener has an unique key.
*/
importListeners(target, list) {
if (qx.core.Environment.get("qx.debug")) {
if (target == null) {
qx.log.Logger.trace(this);
throw new Error("Invalid object: " + target);
}
}
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
targetMap = new Map();
this.__listeners.set(targetKey, targetMap);
}
for (var listKey in list) {
var item = list[listKey];
var entryKey = item.type + (item.capture ? "|capture" : "|bubble");
var entryMap = targetMap.get(entryKey);
if (!entryMap) {
entryMap = new Map();
targetMap.set(entryKey, entryMap)
}
if (entryMap.size === 0) {
// This is the first event listener for this type and target
// Inform the event handler about the new event
// they perform the event registration at DOM level if needed
this.__registerAtHandler(target, item.type, item.capture);
}
// Add listener to map
var unique = item.unique || qx.event.Manager.getNextUniqueId();
entryMap.set(unique, {
handler: item.listener,
context: item.self,
unique: unique
}
);
}
},
/**
* Add an event listener to any valid target. The event listener is passed an
* instance of {@link qx.event.type.Event} containing all relevant information
* about the event as parameter.
*
* @param target {Object} Any valid event target
* @param type {String} Name of the event e.g. "click", "keydown", ...
* @param listener {Function} Event listener function
* @param self {Object ? null} Reference to the 'this' variable inside
* the event listener. When not given, the corresponding dispatcher
* usually falls back to a default, which is the target
* by convention. Note this is not a strict requirement, i.e.
* custom dispatchers can follow a different strategy.
* @param capture {Boolean ? false} Whether to attach the event to the
* capturing phase or the bubbling phase of the event. The default is
* to attach the event handler to the bubbling phase.
* @return {String} An opaque ID, which can be used to remove the event listener
* using the {@link #removeListenerById} method.
* @throws {Error} if the parameters are wrong
*/
addListener(target, type, listener, self, capture) {
if (qx.core.Environment.get("qx.debug")) {
var msg =
"Failed to add event listener for type '" +
type +
"'" +
" to the target '" +
target.classname +
"': ";
qx.core.Assert.assertObject(target, msg + "Invalid Target.");
qx.core.Assert.assertString(type, msg + "Invalid event type.");
qx.core.Assert.assertFunctionOrAsyncFunction(
listener,
msg + "Invalid callback function"
);
if (capture !== undefined) {
qx.core.Assert.assertBoolean(capture, "Invalid capture flag.");
}
}
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
targetMap = new Map();
this.__listeners.set(targetKey, targetMap);
}
var entryKey = type + (capture ? "|capture" : "|bubble");
var entryMap = targetMap.get(entryKey);
if (!entryMap) {
entryMap = new Map();
targetMap.set(entryKey, entryMap)
}
if (entryMap.size === 0) {
// This is the first event listener for this type and target
// Inform the event handler about the new event
// they perform the event registration at DOM level if needed
this.__registerAtHandler(target, type, capture);
}
// Add listener to map
var unique = qx.event.Manager.getNextUniqueId();
entryMap.set(unique, {
handler: listener,
context: self,
unique: unique
}
);
return entryKey + "|" + unique;
},
/**
* Get the event handler class matching the given event target and type
*
* @param target {Object} The event target
* @param type {String} The event type
* @return {qx.event.IEventHandler|null} The best matching event handler or
* <code>null</code>.
*/
findHandler(target, type) {
var isDomNode = false,
isWindow = false,
isObject = false,
isDocument = false;
var key;
if (target.nodeType === 1) {
isDomNode = true;
key = "DOM_" + target.tagName.toLowerCase() + "_" + type;
} else if (target.nodeType === 9) {
isDocument = true;
key = "DOCUMENT_" + type;
}
// Please note:
// Identical operator does not work in IE (as of version 7) because
// document.parentWindow is not identical to window. Crazy stuff.
else if (target == this.__window) {
isWindow = true;
key = "WIN_" + type;
} else if (target.classname) {
isObject = true;
key = "QX_" + target.classname + "_" + type;
} else {
key = "UNKNOWN_" + target + "_" + type;
}
var cache = this.__handlerCache;
if (cache[key]) {
return cache[key];
}
var classes = this.__registration.getHandlers();
var IEventHandler = qx.event.IEventHandler;
var clazz, instance, supportedTypes, targetCheck;
for (var i = 0, l = classes.length; i < l; i++) {
clazz = classes[i];
// shortcut type check
supportedTypes = clazz.SUPPORTED_TYPES;
if (supportedTypes && !supportedTypes[type]) {
continue;
}
// shortcut target check
targetCheck = clazz.TARGET_CHECK;
if (targetCheck) {
// use bitwise & to compare for the bitmask!
var found = false;
if (isDomNode && (targetCheck & IEventHandler.TARGET_DOMNODE) != 0) {
found = true;
} else if (
isWindow &&
(targetCheck & IEventHandler.TARGET_WINDOW) != 0
) {
found = true;
} else if (
isObject &&
(targetCheck & IEventHandler.TARGET_OBJECT) != 0
) {
found = true;
} else if (
isDocument &&
(targetCheck & IEventHandler.TARGET_DOCUMENT) != 0
) {
found = true;
}
if (!found) {
continue;
}
}
instance = this.getHandler(classes[i]);
if (clazz.IGNORE_CAN_HANDLE || instance.canHandleEvent(target, type)) {
cache[key] = instance;
return instance;
}
}
return null;
},
/**
* This method is called each time an event listener for one of the
* supported events is added using {qx.event.Manager#addListener}.
*
* @param target {Object} Any valid event target
* @param type {String} event type
* @param capture {Boolean} Whether to attach the event to the
* capturing phase or the bubbling phase of the event.
* @throws {Error} if there is no handler for the event
*/
__registerAtHandler(target, type, capture) {
var handler = this.findHandler(target, type);
if (handler) {
handler.registerEvent(target, type, capture);
return;
}
if (qx.core.Environment.get("qx.debug")) {
qx.log.Logger.warn(
this,
"There is no event handler for the event '" +
type +
"' on target '" +
target +
"'!"
);
}
},
/**
* Remove an event listener from an event target.
*
* @param target {Object} Any valid event target
* @param type {String} Name of the event
* @param listener {Function} The pointer to the event listener
* @param self {Object ? null} Reference to the 'this' variable inside
* the event listener.
* @param capture {Boolean ? false} Whether to remove the event listener of
* the bubbling or of the capturing phase.
* @return {Boolean} Whether the event was removed successfully (was existant)
* @throws {Error} if the parameters are wrong
*/
removeListener(target, type, listener, self, capture) {
if (qx.core.Environment.get("qx.debug")) {
var msg =
"Failed to remove event listener for type '" +
type +
"'" +
" from the target '" +
target.classname +
"': ";
qx.core.Assert.assertObject(target, msg + "Invalid Target.");
qx.core.Assert.assertString(type, msg + "Invalid event type.");
qx.core.Assert.assertFunction(
listener,
msg + "Invalid callback function"
);
if (self !== undefined) {
qx.core.Assert.assertObject(self, "Invalid context for callback.");
}
if (capture !== undefined) {
qx.core.Assert.assertBoolean(capture, "Invalid capture flag.");
}
}
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
return false;
}
var entryKey = type + (capture ? "|capture" : "|bubble");
var entryMap = targetMap.get(entryKey);
if (!entryMap) {
return false;
}
var deleted = false;
for (const [entryKey, entry] of entryMap.entries().filter(([eK, e]) => e.handler === listener && e.context === self)) {
deleted = true;
entryMap.delete(entryKey);
this.__addToBlacklist(entryKey);
if (entryMap.size === 0) {
this.__unregisterAtHandler(target, type, capture);
}
}
return deleted;
},
/**
* Removes an event listener from an event target by an ID returned by
* {@link #addListener}.
*
* @param target {Object} The event target
* @param id {String} The ID returned by {@link #addListener}
* @return {Boolean} <code>true</code> if the handler was removed
*/
removeListenerById(target, id) {
if (qx.core.Environment.get("qx.debug")) {
var msg =
"Failed to remove event listener for id '" +
id +
"'" +
" from the target '" +
target.classname +
"': ";
qx.core.Assert.assertObject(target, msg + "Invalid Target.");
qx.core.Assert.assertString(id, msg + "Invalid id type.");
}
var split = id.split("|");
var type = split[0];
var capture = split[1].charCodeAt(0) === 99; // detect leading "c"
var unique = split[2];
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
return false;
}
var entryKey = type + (capture ? "|capture" : "|bubble");
var entryMap = targetMap.get(entryKey);
if (!entryMap) {
return false;
}
var entry = entryMap.get(unique);
if (entry) {
entryMap.delete(unique);
this.__addToBlacklist(entry.unique);
if (entryMap.size === 0) {
this.__unregisterAtHandler(target, type, capture);
}
return true;
}
return false;
},
/**
* Remove all event listeners, which are attached to the given event target.
*
* @param target {Object} The event target to remove all event listeners from.
* @return {Boolean} Whether the events were existant and were removed successfully.
*/
removeAllListeners(target) {
var targetKey = target.$$hash || qx.core.ObjectRegistry.toHashCode(target);
var targetMap = this.__listeners.get(targetKey);
if (!targetMap) {
return false;
}
// Deregister from event handlers
var split, type, capture;
for (const [entryKey, entryMap] of targetMap) {
if (entryMap && entryMap.size > 0) {
// This is quite expensive, see bug #1283
split = entryKey.split("|");
for (const uniqueKey of entryMap.keys()) {
this.__addToBlacklist(uniqueKey);
}
entryMap.clear();
type = split[0];
capture = split[1] === "capture";
this.__unregisterAtHandler(target, type, capture);
}
}
this.__listeners.delete(targetKey);
return true;
},
/**
* Internal helper for deleting the internal listener data structure for
* the given targetKey.
*
* @param targetKey {String} Hash code for the object to delete its
* listeners.
*
* @internal
*/
deleteAllListeners(targetKey) {
this.__listeners.delete(targetKey);
},
/**
* This method is called each time the an event listener for one of the
* supported events is removed by using {qx.event.Manager#removeListener}
* and no other event listener is listening on this type.
*
* @param target {Object} Any valid event target
* @param type {String} event type
* @param capture {Boolean} Whether to attach the event to the
* capturing phase or the bubbling phase of the event.
* @throws {Error} if there is no handler for the event
*/
__unregisterAtHandler(target, type, capture) {
var handler = this.findHandler(target, type);
if (handler) {
handler.unregisterEvent(target, type, capture);
return;
}
if (qx.core.Environment.get("qx.debug")) {
qx.log.Logger.warn(
this,
"There is no event handler for the event '" +
type +
"' on target '" +
target +
"'!"
);
}
},
/*
---------------------------------------------------------------------------
EVENT DISPATCH
---------------------------------------------------------------------------
*/
/**
* Dispatches an event object using the qooxdoo event handler system. The
* event will only be visible in event listeners attached using
* {@link #addListener}. After dispatching the event object will be pooled
* for later reuse or disposed.
*
* @param target {Object} Any valid event target
* @param event {qx.event.type.Event} The event object to dispatch. The event
* object must be obtained using {@link qx.event.Registration#createEvent}
* and initialized using {@link qx.event.type.Event#init}.
* @return {Boolean|qx.Promise} whether the event default was prevented or not.
* Returns true, when the event was NOT prevented.
* @throws {Error} if there is no dispatcher for the event
*/
dispatchEvent(target, event) {
if (qx.core.Environment.get("qx.debug")) {
var msg =
"Could not dispatch event '" +
event +
"' on target '" +
target.classname +
"': ";
qx.core.Assert.assertNotUndefined(
target,
msg + "Invalid event target."
);
qx.core.Assert.assertNotNull(target, msg + "Invalid event target.");
qx.core.Assert.assertInstance(
event,
qx.event.type.Event,
msg + "Invalid event object."
);
}
// Show the decentrally fired events to one or more global monitor functions
var monitors = qx.event.Manager.__globalEventMonitors;
if (monitors.length) {
for (var i = 0; i < monitors.length; i++) {
var preventDefault = event.getDefaultPrevented();
try {
monitors[i].call(monitors[i].$$context, target, event);
} catch (ex) {
qx.log.Logger.error(
"Error in global event monitor function " +
monitors[i].toString().slice(0, 50) +
"..."
);
// since 6.0.0-beta-2020051X: throw a real error to stop execution instead of just a warning
throw ex;
}
if (preventDefault != event.getDefaultPrevented()) {
// since 6.0.0-beta-2020051X: throw a real error to stop execution instead of just a warning
throw new Error(
"Unexpected change by global event monitor function, modifications to event " +
event.getType() +
" is not allowed."
);
}
}
}
// Preparations
var type = event.getType();
if (!event.getBubbles() && !this.hasListener(target, type)) {
qx.event.Pool.getInstance().poolObject(event);
return true;
}
if (!event.getTarget()) {
event.setTarget(target);
}
// Interacion data
var classes = this.__registration.getDispatchers();
var instance;
// Loop through the dispatchers
var dispatched = false;
var tracker = {};
for (var i = 0, l = classes.length; i < l; i++) {
instance = this.getDispatcher(classes[i]);
// Ask if the dispatcher can handle this event
if (instance.canDispatchEvent(target, event, type)) {
qx.event.Utils.track(
tracker,
instance.dispatchEvent(target, event, type)
);
dispatched = true;
break;
}
}
if (!dispatched) {
if (qx.core.Environment.get("qx.debug")) {
qx.log.Logger.error(
this,
"No dispatcher can handle event of type " + type + " on " + target
);
}
return true;
}
return qx.event.Utils.then(tracker, function () {
// check whether "preventDefault" has been called
var preventDefault = event.getDefaultPrevented();
// Release the event instance to the event pool
qx.event.Pool.getInstance().poolObject(event);
return !preventDefault;
});
},
/**
* Dispose the event manager
*/
dispose() {
// Remove from manager list
this.__registration.removeManager(this);
qx.util.DisposeUtil.disposeMap(this, "__handlers");
qx.util.DisposeUtil.disposeMap(this, "__dispatchers");
// Dispose data fields
this.__listeners = this.__window = this.__disposeWrapper = null;
this.__registration = this.__handlerCache = null;
},
/**
* Add event to blacklist.
*
* @param uid {String} unique event id
*/
__addToBlacklist(uid) {
if (this.__blacklist === null) {
this.__blacklist = {};
this.__clearBlackList.schedule();
}
this.__blacklist[uid] = true;
},
/**
* Check if the event with the given id has been removed and is therefore blacklisted for event handling
*
* @param uid {String} unique event id
* @return {boolean}
*/
isBlacklisted(uid) {
return this.__blacklist !== null && this.__blacklist[uid] === true;
}
}
});