UNPKG

shaka-player

Version:
186 lines (157 loc) 5.64 kB
/** * @license * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ goog.provide('shaka.util.FakeEventTarget'); goog.require('shaka.asserts'); goog.require('shaka.util.MultiMap'); /** * A work-alike for EventTarget. Only DOM elements may be true EventTargets, * but this can be used as a base class to provide event dispatch to non-DOM * classes. * * @param {shaka.util.FakeEventTarget} parent The parent for the purposes of * event bubbling. Note that events on a FakeEventTarget can only bubble * to other FakeEventTargets. * @struct * @constructor * @implements {EventTarget} * @export */ shaka.util.FakeEventTarget = function(parent) { /** * @private {!shaka.util.MultiMap.<shaka.util.FakeEventTarget.ListenerType>} */ this.listeners_ = new shaka.util.MultiMap(); /** @protected {shaka.util.FakeEventTarget} */ this.parent = parent; }; /** * These are the listener types defined in the closure extern for EventTarget. * @typedef {EventListener|function(!Event):(boolean|undefined)} */ shaka.util.FakeEventTarget.ListenerType; /** * Add an event listener to this object. * * @param {string} type The event type to listen for. * @param {shaka.util.FakeEventTarget.ListenerType} listener The callback or * listener object to invoke. * @param {boolean=} opt_capturing True to listen during the capturing phase, * false to listen during the bubbling phase. Note that FakeEventTarget * does not support the capturing phase from the standard event model. * @override */ shaka.util.FakeEventTarget.prototype.addEventListener = function(type, listener, opt_capturing) { // We don't support the capturing phase. shaka.asserts.assert(!opt_capturing); if (!opt_capturing) { this.listeners_.push(type, listener); } }; /** * Remove an event listener from this object. * * @param {string} type The event type for which you wish to remove a listener. * @param {shaka.util.FakeEventTarget.ListenerType} listener The callback or * listener object to remove. * @param {boolean=} opt_capturing True to remove a listener for the capturing * phase, false to remove a listener for the bubbling phase. Note that * FakeEventTarget does not support the capturing phase from the standard * event model. * @override */ shaka.util.FakeEventTarget.prototype.removeEventListener = function(type, listener, opt_capturing) { // We don't support the capturing phase. shaka.asserts.assert(!opt_capturing); if (!opt_capturing) { this.listeners_.remove(type, listener); } }; /** * Dispatch an event from this object. * * @param {!Event} event The event to be dispatched from this object. * @return {boolean} True if the default action was prevented. * @override */ shaka.util.FakeEventTarget.prototype.dispatchEvent = function(event) { // Overwrite the Event's properties if not already done so (events can be // re-dispatched, so we may be have already done this, so in this case we // can just update the values). Assignment doesn't work in most browsers. // Object.defineProperty seems to work, although some browsers // need the original properties deleted first. if (!event.hasOwnProperty('srcElement')) { delete event.srcElement; Object.defineProperty(event, 'srcElement', { get: function() { return null; } }); } if (event.hasOwnProperty('target')) { event.target = this; } else { delete event.target; var target = this; Object.defineProperty(event, 'target', { get: function() { return target; }, set: function(value) { target = value; } }); } if (event.hasOwnProperty('currentTarget')) { event.currentTarget = null; } else { delete event.currentTarget; var currentTarget = null; Object.defineProperty(event, 'currentTarget', { get: function() { return currentTarget; }, set: function(value) { currentTarget = value; } }); } return this.recursiveDispatch_(event); }; /** * Dispatches an event recursively without changing its original target. * * @param {!Event} event * @return {boolean} True if the default action was prevented. * @private */ shaka.util.FakeEventTarget.prototype.recursiveDispatch_ = function(event) { event.currentTarget = this; var list = this.listeners_.get(event.type) || []; for (var i = 0; i < list.length; ++i) { var listener = list[i]; try { if (listener.handleEvent) { listener.handleEvent(event); } else { listener.call(this, event); } // NOTE: If needed, stopImmediatePropagation() would be checked here. } catch (exception) { // Exceptions during event handlers should not affect the caller, // but should appear on the console as uncaught, according to MDN: // http://goo.gl/N6Ff27 shaka.log.error('Uncaught exception in event handler', exception); } } // NOTE: If needed, stopPropagation() would be checked here. if (this.parent && event.bubbles) { this.parent.recursiveDispatch_(event); } return event.defaultPrevented; };