PageRenderTime 139ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/framework/source/class/qx/bom/Event.js

http://github.com/qooxdoo/qooxdoo
JavaScript | 364 lines | 166 code | 30 blank | 168 comment | 54 complexity | 4dc3c604edaf9d590948cf1f6a76caf5 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-3.0, MIT
  1. /* ************************************************************************
  2. qooxdoo - the new era of web development
  3. http://qooxdoo.org
  4. Copyright:
  5. 2007-2008 1&1 Internet AG, Germany, http://www.1und1.de
  6. License:
  7. MIT: https://opensource.org/licenses/MIT
  8. See the LICENSE file in the project's top-level directory for details.
  9. Authors:
  10. * Fabian Jakobs (fjakobs)
  11. * Sebastian Werner (wpbasti)
  12. * Alexander Steitz (aback)
  13. * Christian Hagendorn (chris_schmidt)
  14. * Tobias Oberrauch (toberrauch) <tobias.oberrauch@1und1.de>
  15. ======================================================================
  16. This class contains code based on the following work:
  17. * Juriy Zaytsev
  18. http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
  19. Copyright (c) 2009 Juriy Zaytsev
  20. License:
  21. BSD: http://github.com/kangax/iseventsupported/blob/master/LICENSE
  22. ----------------------------------------------------------------------
  23. http://github.com/kangax/iseventsupported/blob/master/LICENSE
  24. Copyright (c) 2009 Juriy Zaytsev
  25. Permission is hereby granted, free of charge, to any person
  26. obtaining a copy of this software and associated documentation
  27. files (the "Software"), to deal in the Software without
  28. restriction, including without limitation the rights to use,
  29. copy, modify, merge, publish, distribute, sublicense, and/or sell
  30. copies of the Software, and to permit persons to whom the
  31. Software is furnished to do so, subject to the following
  32. conditions:
  33. The above copyright notice and this permission notice shall be
  34. included in all copies or substantial portions of the Software.
  35. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  36. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  37. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  38. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  39. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  40. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  41. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  42. OTHER DEALINGS IN THE SOFTWARE.
  43. ************************************************************************ */
  44. /**
  45. * Wrapper around native event management capabilities of the browser.
  46. * This class should not be used directly normally. It's better
  47. * to use {@link qx.event.Registration} instead.
  48. */
  49. qx.Bootstrap.define("qx.bom.Event",
  50. {
  51. statics :
  52. {
  53. /**
  54. * Use the low level browser functionality to attach event listeners
  55. * to DOM nodes.
  56. *
  57. * Use this with caution. This is only thought for event handlers and
  58. * qualified developers. These are not mem-leak protected!
  59. *
  60. * @param target {Object} Any valid native event target
  61. * @param type {String} Name of the event
  62. * @param listener {Function} The pointer to the function to assign
  63. * @param useCapture {Boolean ? false} A Boolean value that specifies the event phase to add
  64. * the event handler for the capturing phase or the bubbling phase.
  65. * @param passive {Boolean ? false} Specifies whether to set the passive option to true or false if supported.
  66. */
  67. addNativeListener : function(target, type, listener, useCapture, passive)
  68. {
  69. if (target.addEventListener) {
  70. if (passive === undefined || !qx.core.Environment.get("event.passive")) {
  71. target.addEventListener(type, listener, !!useCapture);
  72. } else {
  73. target.addEventListener(type, listener, { capture: !!useCapture, passive: !!passive });
  74. }
  75. } else if (target.attachEvent) {
  76. target.attachEvent("on" + type, listener);
  77. } else if (typeof target["on" + type] != "undefined") {
  78. target["on" + type] = listener;
  79. } else {
  80. if (qx.core.Environment.get("qx.debug")) {
  81. qx.log.Logger.warn("No method available to add native listener to " + target);
  82. }
  83. }
  84. },
  85. /**
  86. * Use the low level browser functionality to remove event listeners
  87. * from DOM nodes.
  88. *
  89. * @param target {Object} Any valid native event target
  90. * @param type {String} Name of the event
  91. * @param listener {Function} The pointer to the function to assign
  92. * @param useCapture {Boolean ? false} A Boolean value that specifies the event phase to remove
  93. * the event handler for the capturing phase or the bubbling phase.
  94. */
  95. removeNativeListener : function(target, type, listener, useCapture)
  96. {
  97. if (target.removeEventListener)
  98. {
  99. target.removeEventListener(type, listener, !!useCapture);
  100. }
  101. else if (target.detachEvent)
  102. {
  103. try {
  104. target.detachEvent("on" + type, listener);
  105. }
  106. catch(e)
  107. {
  108. // IE7 sometimes dispatches "unload" events on protected windows
  109. // Ignore the "permission denied" errors.
  110. if(e.number !== -2146828218) {
  111. throw e;
  112. };
  113. }
  114. }
  115. else if (typeof target["on" + type] != "undefined")
  116. {
  117. target["on" + type] = null;
  118. }
  119. else
  120. {
  121. if (qx.core.Environment.get("qx.debug")) {
  122. qx.log.Logger.warn("No method available to remove native listener from " + target);
  123. }
  124. }
  125. },
  126. /**
  127. * Returns the target of the event.
  128. *
  129. * @param e {Event} Native event object
  130. * @return {Object} Any valid native event target
  131. */
  132. getTarget : function(e) {
  133. return e.target || e.srcElement;
  134. },
  135. /**
  136. * Computes the related target from the native DOM event
  137. *
  138. * @param e {Event} Native DOM event object
  139. * @return {Element} The related target
  140. */
  141. getRelatedTarget : function(e)
  142. {
  143. if (e.relatedTarget !== undefined)
  144. {
  145. // In Firefox the related target of mouse events is sometimes an
  146. // anonymous div inside of a text area, which raises an exception if
  147. // the nodeType is read. This is why the try/catch block is needed.
  148. if ((qx.core.Environment.get("engine.name") == "gecko"))
  149. {
  150. try {
  151. e.relatedTarget && e.relatedTarget.nodeType;
  152. } catch (ex) {
  153. return null;
  154. }
  155. }
  156. return e.relatedTarget;
  157. }
  158. else if (e.fromElement !== undefined &&
  159. (e.type === "mouseover" || e.type === "pointerover"))
  160. {
  161. return e.fromElement;
  162. } else if (e.toElement !== undefined) {
  163. return e.toElement;
  164. } else {
  165. return null;
  166. }
  167. },
  168. /**
  169. * Prevent the native default of the event to be processed.
  170. *
  171. * This is useful to stop native keybindings, native selection
  172. * and other native functionality behind events.
  173. *
  174. * @param e {Event} Native event object
  175. */
  176. preventDefault : function(e)
  177. {
  178. if (e.preventDefault) {
  179. e.preventDefault();
  180. }
  181. else {
  182. try {
  183. // this allows us to prevent some key press events in IE.
  184. // See bug #1049
  185. e.keyCode = 0;
  186. } catch(ex) {}
  187. e.returnValue = false;
  188. }
  189. },
  190. /**
  191. * Stops the propagation of the given event to the parent element.
  192. *
  193. * Only useful for events which bubble e.g. mousedown.
  194. *
  195. * @param e {Event} Native event object
  196. */
  197. stopPropagation : function(e)
  198. {
  199. if (e.stopPropagation) {
  200. e.stopPropagation();
  201. } else {
  202. e.cancelBubble = true;
  203. }
  204. },
  205. /**
  206. * Fires a synthetic native event on the given element.
  207. *
  208. * @param target {Element} DOM element to fire event on
  209. * @param type {String} Name of the event to fire
  210. * @return {Boolean} A value that indicates whether any of the event handlers called {@link #preventDefault}.
  211. * <code>true</code> The default action is permitted, <code>false</code> the caller should prevent the default action.
  212. */
  213. fire : function(target, type)
  214. {
  215. // dispatch for standard first
  216. if (document.createEvent)
  217. {
  218. var evt = document.createEvent("HTMLEvents");
  219. evt.initEvent(type, true, true);
  220. return !target.dispatchEvent(evt);
  221. }
  222. // dispatch for IE
  223. else
  224. {
  225. var evt = document.createEventObject();
  226. return target.fireEvent("on" + type, evt);
  227. }
  228. },
  229. /**
  230. * Whether the given target supports the given event type.
  231. *
  232. * Useful for testing for support of new features like
  233. * touch events, gesture events, orientation change, on/offline, etc.
  234. *
  235. * *NOTE:* This check is *case-insensitive*.
  236. * <code>supportsEvent(window, "cLicK")</code> will return <code>true</code>
  237. * but <code>window.addEventListener("cLicK", callback)</code> will fail
  238. * silently!
  239. *
  240. * @param target {var} Any valid target e.g. window, dom node, etc.
  241. * @param type {String} Type of the event e.g. click, mousedown
  242. * @return {Boolean} Whether the given event is supported
  243. */
  244. supportsEvent : function(target, type)
  245. {
  246. var browserName = qx.core.Environment.get("browser.name");
  247. var engineName = qx.core.Environment.get("engine.name");
  248. // transitionEnd support can not be detected generically for Internet Explorer 10+ [BUG #7875]
  249. if (type.toLowerCase().indexOf("transitionend") != -1
  250. && engineName === "mshtml"
  251. && qx.core.Environment.get("browser.documentmode") > 9)
  252. {
  253. return true;
  254. }
  255. /**
  256. * add exception for safari mobile ()
  257. * @see http://bugzilla.qooxdoo.org/show_bug.cgi?id=8244
  258. */
  259. var safariBrowserNames = ["mobile safari", "safari"];
  260. if (
  261. engineName === "webkit" &&
  262. safariBrowserNames.indexOf(browserName) > -1
  263. ) {
  264. var supportedEvents = [
  265. 'loadeddata', 'progress', 'timeupdate', 'seeked', 'canplay', 'play',
  266. 'playing', 'pause', 'loadedmetadata', 'ended', 'volumechange'
  267. ];
  268. if (supportedEvents.indexOf(type.toLowerCase()) > -1) {
  269. return true;
  270. }
  271. }
  272. // The 'transitionend' event can only be detected on window objects,
  273. // not DOM elements [BUG #7249]
  274. if (target != window && type.toLowerCase().indexOf("transitionend") != -1) {
  275. var transitionSupport = qx.core.Environment.get("css.transition");
  276. return (transitionSupport && transitionSupport["end-event"] == type);
  277. }
  278. // Using the lowercase representation is important for the
  279. // detection of events like 'MSPointer*'. They have to detected
  280. // using the lower case name of the event.
  281. var eventName = "on" + type.toLowerCase();
  282. var supportsEvent = (eventName in target);
  283. if (!supportsEvent)
  284. {
  285. supportsEvent = typeof target[eventName] == "function";
  286. if (!supportsEvent && target.setAttribute)
  287. {
  288. target.setAttribute(eventName, "return;");
  289. supportsEvent = typeof target[eventName] == "function";
  290. target.removeAttribute(eventName);
  291. }
  292. }
  293. return supportsEvent;
  294. },
  295. /**
  296. * Returns the (possibly vendor-prefixed) name of the given event type.
  297. * *NOTE:* Incorrect capitalization of type names will *not* be corrected. See
  298. * {@link #supportsEvent} for details.
  299. *
  300. * @param target {var} Any valid target e.g. window, dom node, etc.
  301. * @param type {String} Type of the event e.g. click, mousedown
  302. * @return {String|null} Event name or <code>null</code> if the event is not
  303. * supported.
  304. */
  305. getEventName : function(target, type)
  306. {
  307. var pref = [""].concat(qx.bom.Style.VENDOR_PREFIXES);
  308. for (var i=0, l=pref.length; i<l; i++) {
  309. var prefix = pref[i].toLowerCase();
  310. if (qx.bom.Event.supportsEvent(target, prefix + type)) {
  311. return prefix ? prefix + qx.lang.String.firstUp(type) : type;
  312. }
  313. }
  314. return null;
  315. }
  316. }
  317. });