Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
var 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
 */
13
H5P.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
 
73
H5P.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
})();