Source: main/webapp/modules/Event.js

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var Guacamole = Guacamole || {};
  20. /**
  21. * An arbitrary event, emitted by a {@link Guacamole.Event.Target}. This object
  22. * should normally serve as the base class for a different object that is more
  23. * specific to the event type.
  24. *
  25. * @constructor
  26. * @param {!string} type
  27. * The unique name of this event type.
  28. */
  29. Guacamole.Event = function Event(type) {
  30. /**
  31. * The unique name of this event type.
  32. *
  33. * @type {!string}
  34. */
  35. this.type = type;
  36. /**
  37. * An arbitrary timestamp in milliseconds, indicating this event's
  38. * position in time relative to other events.
  39. *
  40. * @type {!number}
  41. */
  42. this.timestamp = new Date().getTime();
  43. /**
  44. * Returns the number of milliseconds elapsed since this event was created.
  45. *
  46. * @return {!number}
  47. * The number of milliseconds elapsed since this event was created.
  48. */
  49. this.getAge = function getAge() {
  50. return new Date().getTime() - this.timestamp;
  51. };
  52. /**
  53. * Requests that the legacy event handler associated with this event be
  54. * invoked on the given event target. This function will be invoked
  55. * automatically by implementations of {@link Guacamole.Event.Target}
  56. * whenever {@link Guacamole.Event.Target#emit emit()} is invoked.
  57. * <p>
  58. * Older versions of Guacamole relied on single event handlers with the
  59. * prefix "on", such as "onmousedown" or "onkeyup". If a Guacamole.Event
  60. * implementation is replacing the event previously represented by one of
  61. * these handlers, this function gives the implementation the opportunity
  62. * to provide backward compatibility with the old handler.
  63. * <p>
  64. * Unless overridden, this function does nothing.
  65. *
  66. * @param {!Guacamole.Event.Target} eventTarget
  67. * The {@link Guacamole.Event.Target} that emitted this event.
  68. */
  69. this.invokeLegacyHandler = function invokeLegacyHandler(eventTarget) {
  70. // Do nothing
  71. };
  72. };
  73. /**
  74. * A {@link Guacamole.Event} that may relate to one or more DOM events.
  75. * Continued propagation and default behavior of the related DOM events may be
  76. * prevented with {@link Guacamole.Event.DOMEvent#stopPropagation stopPropagation()}
  77. * and {@link Guacamole.Event.DOMEvent#preventDefault preventDefault()}
  78. * respectively.
  79. *
  80. * @constructor
  81. * @augments Guacamole.Event
  82. *
  83. * @param {!string} type
  84. * The unique name of this event type.
  85. *
  86. * @param {Event|Event[]} [events=[]]
  87. * The DOM events that are related to this event, if any. Future calls to
  88. * {@link Guacamole.Event.DOMEvent#preventDefault preventDefault()} and
  89. * {@link Guacamole.Event.DOMEvent#stopPropagation stopPropagation()} will
  90. * affect these events.
  91. */
  92. Guacamole.Event.DOMEvent = function DOMEvent(type, events) {
  93. Guacamole.Event.call(this, type);
  94. // Default to empty array
  95. events = events || [];
  96. // Automatically wrap non-array single Event in an array
  97. if (!Array.isArray(events))
  98. events = [ events ];
  99. /**
  100. * Requests that the default behavior of related DOM events be prevented.
  101. * Whether this request will be honored by the browser depends on the
  102. * nature of those events and the timing of the request.
  103. */
  104. this.preventDefault = function preventDefault() {
  105. events.forEach(function applyPreventDefault(event) {
  106. if (event.preventDefault) event.preventDefault();
  107. event.returnValue = false;
  108. });
  109. };
  110. /**
  111. * Stops further propagation of related events through the DOM. Only events
  112. * that are directly related to this event will be stopped.
  113. */
  114. this.stopPropagation = function stopPropagation() {
  115. events.forEach(function applyStopPropagation(event) {
  116. event.stopPropagation();
  117. });
  118. };
  119. };
  120. /**
  121. * Convenience function for cancelling all further processing of a given DOM
  122. * event. Invoking this function prevents the default behavior of the event and
  123. * stops any further propagation.
  124. *
  125. * @param {!Event} event
  126. * The DOM event to cancel.
  127. */
  128. Guacamole.Event.DOMEvent.cancelEvent = function cancelEvent(event) {
  129. event.stopPropagation();
  130. if (event.preventDefault) event.preventDefault();
  131. event.returnValue = false;
  132. };
  133. /**
  134. * An object which can dispatch {@link Guacamole.Event} objects. Listeners
  135. * registered with {@link Guacamole.Event.Target#on on()} will automatically
  136. * be invoked based on the type of {@link Guacamole.Event} passed to
  137. * {@link Guacamole.Event.Target#dispatch dispatch()}. It is normally
  138. * subclasses of Guacamole.Event.Target that will dispatch events, and usages
  139. * of those subclasses that will catch dispatched events with on().
  140. *
  141. * @constructor
  142. */
  143. Guacamole.Event.Target = function Target() {
  144. /**
  145. * A callback function which handles an event dispatched by an event
  146. * target.
  147. *
  148. * @callback Guacamole.Event.Target~listener
  149. * @param {!Guacamole.Event} event
  150. * The event that was dispatched.
  151. *
  152. * @param {!Guacamole.Event.Target} target
  153. * The object that dispatched the event.
  154. */
  155. /**
  156. * All listeners (callback functions) registered for each event type passed
  157. * to {@link Guacamole.Event.Targer#on on()}.
  158. *
  159. * @private
  160. * @type {!Object.<string, Guacamole.Event.Target~listener[]>}
  161. */
  162. var listeners = {};
  163. /**
  164. * Registers a listener for events having the given type, as dictated by
  165. * the {@link Guacamole.Event#type type} property of {@link Guacamole.Event}
  166. * provided to {@link Guacamole.Event.Target#dispatch dispatch()}.
  167. *
  168. * @param {!string} type
  169. * The unique name of this event type.
  170. *
  171. * @param {!Guacamole.Event.Target~listener} listener
  172. * The function to invoke when an event having the given type is
  173. * dispatched. The {@link Guacamole.Event} object provided to
  174. * {@link Guacamole.Event.Target#dispatch dispatch()} will be passed to
  175. * this function, along with the dispatching Guacamole.Event.Target.
  176. */
  177. this.on = function on(type, listener) {
  178. var relevantListeners = listeners[type];
  179. if (!relevantListeners)
  180. listeners[type] = relevantListeners = [];
  181. relevantListeners.push(listener);
  182. };
  183. /**
  184. * Registers a listener for events having the given types, as dictated by
  185. * the {@link Guacamole.Event#type type} property of {@link Guacamole.Event}
  186. * provided to {@link Guacamole.Event.Target#dispatch dispatch()}.
  187. * <p>
  188. * Invoking this function is equivalent to manually invoking
  189. * {@link Guacamole.Event.Target#on on()} for each of the provided types.
  190. *
  191. * @param {!string[]} types
  192. * The unique names of the event types to associate with the given
  193. * listener.
  194. *
  195. * @param {!Guacamole.Event.Target~listener} listener
  196. * The function to invoke when an event having any of the given types
  197. * is dispatched. The {@link Guacamole.Event} object provided to
  198. * {@link Guacamole.Event.Target#dispatch dispatch()} will be passed to
  199. * this function, along with the dispatching Guacamole.Event.Target.
  200. */
  201. this.onEach = function onEach(types, listener) {
  202. types.forEach(function addListener(type) {
  203. this.on(type, listener);
  204. }, this);
  205. };
  206. /**
  207. * Dispatches the given event, invoking all event handlers registered with
  208. * this Guacamole.Event.Target for that event's
  209. * {@link Guacamole.Event#type type}.
  210. *
  211. * @param {!Guacamole.Event} event
  212. * The event to dispatch.
  213. */
  214. this.dispatch = function dispatch(event) {
  215. // Invoke any relevant legacy handler for the event
  216. event.invokeLegacyHandler(this);
  217. // Invoke all registered listeners
  218. var relevantListeners = listeners[event.type];
  219. if (relevantListeners) {
  220. for (var i = 0; i < relevantListeners.length; i++) {
  221. relevantListeners[i](event, this);
  222. }
  223. }
  224. };
  225. /**
  226. * Unregisters a listener that was previously registered with
  227. * {@link Guacamole.Event.Target#on on()} or
  228. * {@link Guacamole.Event.Target#onEach onEach()}. If no such listener was
  229. * registered, this function has no effect. If multiple copies of the same
  230. * listener were registered, the first listener still registered will be
  231. * removed.
  232. *
  233. * @param {!string} type
  234. * The unique name of the event type handled by the listener being
  235. * removed.
  236. *
  237. * @param {!Guacamole.Event.Target~listener} listener
  238. * The listener function previously provided to
  239. * {@link Guacamole.Event.Target#on on()}or
  240. * {@link Guacamole.Event.Target#onEach onEach()}.
  241. *
  242. * @returns {!boolean}
  243. * true if the specified listener was removed, false otherwise.
  244. */
  245. this.off = function off(type, listener) {
  246. var relevantListeners = listeners[type];
  247. if (!relevantListeners)
  248. return false;
  249. for (var i = 0; i < relevantListeners.length; i++) {
  250. if (relevantListeners[i] === listener) {
  251. relevantListeners.splice(i, 1);
  252. return true;
  253. }
  254. }
  255. return false;
  256. };
  257. /**
  258. * Unregisters listeners that were previously registered with
  259. * {@link Guacamole.Event.Target#on on()} or
  260. * {@link Guacamole.Event.Target#onEach onEach()}. If no such listeners
  261. * were registered, this function has no effect. If multiple copies of the
  262. * same listener were registered for the same event type, the first
  263. * listener still registered will be removed.
  264. * <p>
  265. * Invoking this function is equivalent to manually invoking
  266. * {@link Guacamole.Event.Target#off off()} for each of the provided types.
  267. *
  268. * @param {!string[]} types
  269. * The unique names of the event types handled by the listeners being
  270. * removed.
  271. *
  272. * @param {!Guacamole.Event.Target~listener} listener
  273. * The listener function previously provided to
  274. * {@link Guacamole.Event.Target#on on()} or
  275. * {@link Guacamole.Event.Target#onEach onEach()}.
  276. *
  277. * @returns {!boolean}
  278. * true if any of the specified listeners were removed, false
  279. * otherwise.
  280. */
  281. this.offEach = function offEach(types, listener) {
  282. var changed = false;
  283. types.forEach(function removeListener(type) {
  284. changed |= this.off(type, listener);
  285. }, this);
  286. return changed;
  287. };
  288. };