PageSourceSearch

https://h5p.org/sites/all/modules/h5p/library/js/h5p-event-dispatcher.js?the41y

js h5p.org collected 2026-09-24 07:20:24 UTC 6,442 bytes, 258 lines download raw bytes

1var H5P = window.H5P = window.H5P || {};
2
3/**
4 * The Event class for the EventDispatcher.
5 *
6 * @class
7 * @param {string} type
8 * @param {*} data
9 * @param {Object} [extras]
10 * @param {boolean} [extras.bubbles]
11 * @param {boolean} [extras.external]
12 */
13H5P.Event = function (type, data, extras) {
14  this.type = type;
15  this.data = data;
16  var bubbles = false;
17
18  // Is this an external event?
19  var external = false;
20
21  // Is this event scheduled to be sent externally?
22  var scheduledForExternal = false;
23
24  if (extras === undefined) {
25    extras = {};
26  }
27  if (extras.bubbles === true) {
28    bubbles = true;
29  }
30  if (extras.external === true) {
31    external = true;
32  }
33
34  /**
35   * Prevent this event from bubbling up to parent
36   */
37  this.preventBubbling = function () {
38    bubbles = false;
39  };
40
41  /**
42   * Get bubbling status
43   *
44   * @returns {boolean}
45   *   true if bubbling false otherwise
46   */
47  this.getBubbles = function () {
48    return bubbles;
49  };
50
51  /**
52   * Try to schedule an event for externalDispatcher
53   *
54   * @returns {boolean}
55   *   true if external and not already scheduled, otherwise false
56   */
57  this.scheduleForExternal = function () {
58    if (external && !scheduledForExternal) {
59      scheduledForExternal = true;
60      return true;
61    }
62    return false;
63  };
64};
65
66/**
67 * Callback type for event listeners.
68 *
69 * @callback H5P.EventCallback
70 * @param {H5P.Event} event
71 */
72
73H5P.EventDispatcher = (function () {
74
75  /**
76   * The base of the event system.
77   * Inherit this class if you want your H5P to dispatch events.
78   *
79   * @class
80   * @memberof H5P
81   */
82  function EventDispatcher() {
83    var self = this;
84
85    /**
86     * Keep track of listeners for each event.
87     *
88     * @private
89     * @type {Object}
90     */
91    var triggers = {};
92
93    /**
94     * Add new event listener.
95     *
96     * @throws {TypeError}
97     *   listener must be a function
98     * @param {string} type
99     *   Event type
100     * @param {H5P.EventCallback} listener
101     *   Event listener
102     * @param {Object} [thisArg]
103     *   Optionally specify the this value when calling listener.
104     */
105    this.on = function (type, listener, thisArg) {
106      if (typeof listener !== 'function') {
107        throw TypeError('listener must be a function');
108      }
109
110      // Trigger event before adding to avoid recursion
111      self.trigger('newListener', {'type': type, 'listener': listener});
112
113      var trigger = {'listener': listener, 'thisArg': thisArg};
114      if (!triggers[type]) {
115        // First
116        triggers[type] = [trigger];
117      }
118      else {
119        // Append
120        triggers[type].push(trigger);
121      }
122    };
123
124    /**
125     * Add new event listener that will be fired only once.
126     *
127     * @throws {TypeError}
128     *   listener must be a function
129     * @param {string} type
130     *   Event type
131     * @param {H5P.EventCallback} listener
132     *   Event listener
133     * @param {Object} thisArg
134     *   Optionally specify the this value when calling listener.
135     */
136    this.once = function (type, listener, thisArg) {
137      if (!(listener instanceof Function)) {
138        throw TypeError('listener must be a function');
139      }
140
141      var once = function (event) {
142        self.off(event.type, once);
143        listener.call(this, event);
144      };
145
146      self.on(type, once, thisArg);
147    };
148
149    /**
150     * Remove event listener.
151     * If no listener is specified, all listeners will be removed.
152     *
153     * @throws {TypeError}
154     *   listener must be a function
155     * @param {string} type
156     *   Event type
157     * @param {H5P.EventCallback} listener
158     *   Event listener
159     */
160    this.off = function (type, listener) {
161      if (listener !== undefined && !(listener instanceof Function)) {
162        throw TypeError('listener must be a function');
163      }
164
165      if (triggers[type] === undefined) {
166        return;
167      }
168
169      if (listener === undefined) {
170        // Remove all listeners
171        delete triggers[type];
172        self.trigger('removeListener', type);
173        return;
174      }
175
176      // Find specific listener
177      for (var i = 0; i < triggers[type].length; i++) {
178        if (triggers[type][i].listener === listener) {
179          triggers[type].splice(i, 1);
180          self.trigger('removeListener', type, {'listener': listener});
181          break;
182        }
183      }
184
185      // Clean up empty arrays
186      if (!triggers[type].length) {
187        delete triggers[type];
188      }
189    };
190
191    /**
192     * Try to call all event listeners for the given event type.
193     *
194     * @private
195     * @param {string} Event type
196     */
197    var call = function (type, event) {
198      if (triggers[type] === undefined) {
199        return;
200      }
201
202      // Clone array (prevents triggers from being modified during the event)
203      var handlers = triggers[type].slice();
204
205      // Call all listeners
206      for (var i = 0; i < handlers.length; i++) {
207        var trigger = handlers[i];
208        var thisArg = (trigger.thisArg ? trigger.thisArg : this);
209        trigger.listener.call(thisArg, event);
210      }
211    };
212
213    /**
214     * Dispatch event.
215     *
216     * @param {string|H5P.Event} event
217     *   Event object or event type as string
218     * @param {*} [eventData]
219     *   Custom event data(used when event type as string is used as first
220     *   argument).
221     * @param {Object} [extras]
222     * @param {boolean} [extras.bubbles]
223     * @param {boolean} [extras.external]
224     */
225    this.trigger = function (event, eventData, extras) {
226      if (event === undefined) {
227        return;
228      }
229      if (event instanceof String || typeof event === 'string') {
230        event = new H5P.Event(event, eventData, extras);
231      }
232      else if (eventData !== undefined) {
233        event.data = eventData;
234      }
235
236      // Check to see if this event should go externally after all triggering and bubbling is done
237      var scheduledForExternal = event.scheduleForExternal();
238
239      // Call all listeners
240      call.call(this, event.type, event);
241
242      // Call all * listeners
243      call.call(this, '*', event);
244
245      // Bubble
246      if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher &&
247          (self.parent.trigger instanceof Function || typeof self.parent.trigger === 'function')) {
248        self.parent.trigger(event);
249      }
250
251      if (scheduledForExternal) {
252        H5P.externalDispatcher.trigger.call(this, event);
253      }
254    };
255  }
256
257  return EventDispatcher;
258})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.