UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

365 lines (317 loc) 12.1 kB
/* ************************************************************************ 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) * Alexander Steitz (aback) * Christian Hagendorn (chris_schmidt) * Tobias Oberrauch (toberrauch) <tobias.oberrauch@1und1.de> ====================================================================== This class contains code based on the following work: * Juriy Zaytsev http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ Copyright (c) 2009 Juriy Zaytsev License: BSD: http://github.com/kangax/iseventsupported/blob/master/LICENSE ---------------------------------------------------------------------- http://github.com/kangax/iseventsupported/blob/master/LICENSE Copyright (c) 2009 Juriy Zaytsev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ************************************************************************ */ /** * Wrapper around native event management capabilities of the browser. * This class should not be used directly normally. It's better * to use {@link qx.event.Registration} instead. */ qx.Bootstrap.define("qx.bom.Event", { statics : { /** * Use the low level browser functionality to attach event listeners * to DOM nodes. * * Use this with caution. This is only thought for event handlers and * qualified developers. These are not mem-leak protected! * * @param target {Object} Any valid native event target * @param type {String} Name of the event * @param listener {Function} The pointer to the function to assign * @param useCapture {Boolean ? false} A Boolean value that specifies the event phase to add * the event handler for the capturing phase or the bubbling phase. * @param passive {Boolean ? false} Specifies whether to set the passive option to true or false if supported. */ addNativeListener : function(target, type, listener, useCapture, passive) { if (target.addEventListener) { if (passive === undefined || !qx.core.Environment.get("event.passive")) { target.addEventListener(type, listener, !!useCapture); } else { target.addEventListener(type, listener, { capture: !!useCapture, passive: !!passive }); } } else if (target.attachEvent) { target.attachEvent("on" + type, listener); } else if (typeof target["on" + type] != "undefined") { target["on" + type] = listener; } else { if (qx.core.Environment.get("qx.debug")) { qx.log.Logger.warn("No method available to add native listener to " + target); } } }, /** * Use the low level browser functionality to remove event listeners * from DOM nodes. * * @param target {Object} Any valid native event target * @param type {String} Name of the event * @param listener {Function} The pointer to the function to assign * @param useCapture {Boolean ? false} A Boolean value that specifies the event phase to remove * the event handler for the capturing phase or the bubbling phase. */ removeNativeListener : function(target, type, listener, useCapture) { if (target.removeEventListener) { target.removeEventListener(type, listener, !!useCapture); } else if (target.detachEvent) { try { target.detachEvent("on" + type, listener); } catch(e) { // IE7 sometimes dispatches "unload" events on protected windows // Ignore the "permission denied" errors. if(e.number !== -2146828218) { throw e; }; } } else if (typeof target["on" + type] != "undefined") { target["on" + type] = null; } else { if (qx.core.Environment.get("qx.debug")) { qx.log.Logger.warn("No method available to remove native listener from " + target); } } }, /** * Returns the target of the event. * * @param e {Event} Native event object * @return {Object} Any valid native event target */ getTarget : function(e) { return e.target || e.srcElement; }, /** * Computes the related target from the native DOM event * * @param e {Event} Native DOM event object * @return {Element} The related target */ getRelatedTarget : function(e) { if (e.relatedTarget !== undefined) { // In Firefox the related target of mouse events is sometimes an // anonymous div inside of a text area, which raises an exception if // the nodeType is read. This is why the try/catch block is needed. if ((qx.core.Environment.get("engine.name") == "gecko")) { try { e.relatedTarget && e.relatedTarget.nodeType; } catch (ex) { return null; } } return e.relatedTarget; } else if (e.fromElement !== undefined && (e.type === "mouseover" || e.type === "pointerover")) { return e.fromElement; } else if (e.toElement !== undefined) { return e.toElement; } else { return null; } }, /** * Prevent the native default of the event to be processed. * * This is useful to stop native keybindings, native selection * and other native functionality behind events. * * @param e {Event} Native event object */ preventDefault : function(e) { if (e.preventDefault) { e.preventDefault(); } else { try { // this allows us to prevent some key press events in IE. // See bug #1049 e.keyCode = 0; } catch(ex) {} e.returnValue = false; } }, /** * Stops the propagation of the given event to the parent element. * * Only useful for events which bubble e.g. mousedown. * * @param e {Event} Native event object */ stopPropagation : function(e) { if (e.stopPropagation) { e.stopPropagation(); } else { e.cancelBubble = true; } }, /** * Fires a synthetic native event on the given element. * * @param target {Element} DOM element to fire event on * @param type {String} Name of the event to fire * @return {Boolean} A value that indicates whether any of the event handlers called {@link #preventDefault}. * <code>true</code> The default action is permitted, <code>false</code> the caller should prevent the default action. */ fire : function(target, type) { // dispatch for standard first if (document.createEvent) { var evt = document.createEvent("HTMLEvents"); evt.initEvent(type, true, true); return !target.dispatchEvent(evt); } // dispatch for IE else { var evt = document.createEventObject(); return target.fireEvent("on" + type, evt); } }, /** * Whether the given target supports the given event type. * * Useful for testing for support of new features like * touch events, gesture events, orientation change, on/offline, etc. * * *NOTE:* This check is *case-insensitive*. * <code>supportsEvent(window, "cLicK")</code> will return <code>true</code> * but <code>window.addEventListener("cLicK", callback)</code> will fail * silently! * * @param target {var} Any valid target e.g. window, dom node, etc. * @param type {String} Type of the event e.g. click, mousedown * @return {Boolean} Whether the given event is supported */ supportsEvent : function(target, type) { var browserName = qx.core.Environment.get("browser.name"); var engineName = qx.core.Environment.get("engine.name"); // transitionEnd support can not be detected generically for Internet Explorer 10+ [BUG #7875] if (type.toLowerCase().indexOf("transitionend") != -1 && engineName === "mshtml" && qx.core.Environment.get("browser.documentmode") > 9) { return true; } /** * add exception for safari mobile () * @see http://bugzilla.qooxdoo.org/show_bug.cgi?id=8244 */ var safariBrowserNames = ["mobile safari", "safari"]; if ( engineName === "webkit" && safariBrowserNames.indexOf(browserName) > -1 ) { var supportedEvents = [ 'loadeddata', 'progress', 'timeupdate', 'seeked', 'canplay', 'play', 'playing', 'pause', 'loadedmetadata', 'ended', 'volumechange' ]; if (supportedEvents.indexOf(type.toLowerCase()) > -1) { return true; } } // The 'transitionend' event can only be detected on window objects, // not DOM elements [BUG #7249] if (target != window && type.toLowerCase().indexOf("transitionend") != -1) { var transitionSupport = qx.core.Environment.get("css.transition"); return (transitionSupport && transitionSupport["end-event"] == type); } // Using the lowercase representation is important for the // detection of events like 'MSPointer*'. They have to detected // using the lower case name of the event. var eventName = "on" + type.toLowerCase(); var supportsEvent = (eventName in target); if (!supportsEvent) { supportsEvent = typeof target[eventName] == "function"; if (!supportsEvent && target.setAttribute) { target.setAttribute(eventName, "return;"); supportsEvent = typeof target[eventName] == "function"; target.removeAttribute(eventName); } } return supportsEvent; }, /** * Returns the (possibly vendor-prefixed) name of the given event type. * *NOTE:* Incorrect capitalization of type names will *not* be corrected. See * {@link #supportsEvent} for details. * * @param target {var} Any valid target e.g. window, dom node, etc. * @param type {String} Type of the event e.g. click, mousedown * @return {String|null} Event name or <code>null</code> if the event is not * supported. */ getEventName : function(target, type) { var pref = [""].concat(qx.bom.Style.VENDOR_PREFIXES); for (var i=0, l=pref.length; i<l; i++) { var prefix = pref[i].toLowerCase(); if (qx.bom.Event.supportsEvent(target, prefix + type)) { return prefix ? prefix + qx.lang.String.firstUp(type) : type; } } return null; } } });