http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/browserevent.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/browserevent.js b/externs/GCL/externs/goog/events/browserevent.js new file mode 100644 index 0000000..f0773ce --- /dev/null +++ b/externs/GCL/externs/goog/events/browserevent.js @@ -0,0 +1,386 @@ +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// 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. + +/** + * @fileoverview A patched, standardized event object for browser events. + * + * <pre> + * The patched event object contains the following members: + * - type {string} Event type, e.g. 'click' + * - target {Object} The element that actually triggered the event + * - currentTarget {Object} The element the listener is attached to + * - relatedTarget {Object} For mouseover and mouseout, the previous object + * - offsetX {number} X-coordinate relative to target + * - offsetY {number} Y-coordinate relative to target + * - clientX {number} X-coordinate relative to viewport + * - clientY {number} Y-coordinate relative to viewport + * - screenX {number} X-coordinate relative to the edge of the screen + * - screenY {number} Y-coordinate relative to the edge of the screen + * - button {number} Mouse button. Use isButton() to test. + * - keyCode {number} Key-code + * - ctrlKey {boolean} Was ctrl key depressed + * - altKey {boolean} Was alt key depressed + * - shiftKey {boolean} Was shift key depressed + * - metaKey {boolean} Was meta key depressed + * - defaultPrevented {boolean} Whether the default action has been prevented + * - state {Object} History state object + * + * NOTE: The keyCode member contains the raw browser keyCode. For normalized + * key and character code use {@link goog.events.KeyHandler}. + * </pre> + * + * @author [email protected] (Erik Arvidsson) + */ + +goog.provide('goog.events.BrowserEvent'); +goog.provide('goog.events.BrowserEvent.MouseButton'); + +goog.require('goog.events.BrowserFeature'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.reflect'); +goog.require('goog.userAgent'); + + + +/** + * Accepts a browser event object and creates a patched, cross browser event + * object. + * The content of this object will not be initialized if no event object is + * provided. If this is the case, init() needs to be invoked separately. + * @param {Event=} opt_e Browser event object. + * @param {EventTarget=} opt_currentTarget Current target for event. + * @constructor + * @extends {goog.events.Event} + */ +goog.events.BrowserEvent = function(opt_e, opt_currentTarget) { + goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : ''); + + /** + * Target that fired the event. + * @override + * @type {Node} + */ + this.target = null; + + /** + * Node that had the listener attached. + * @override + * @type {Node|undefined} + */ + this.currentTarget = null; + + /** + * For mouseover and mouseout events, the related object for the event. + * @type {Node} + */ + this.relatedTarget = null; + + /** + * X-coordinate relative to target. + * @type {number} + */ + this.offsetX = 0; + + /** + * Y-coordinate relative to target. + * @type {number} + */ + this.offsetY = 0; + + /** + * X-coordinate relative to the window. + * @type {number} + */ + this.clientX = 0; + + /** + * Y-coordinate relative to the window. + * @type {number} + */ + this.clientY = 0; + + /** + * X-coordinate relative to the monitor. + * @type {number} + */ + this.screenX = 0; + + /** + * Y-coordinate relative to the monitor. + * @type {number} + */ + this.screenY = 0; + + /** + * Which mouse button was pressed. + * @type {number} + */ + this.button = 0; + + /** + * Keycode of key press. + * @type {number} + */ + this.keyCode = 0; + + /** + * Keycode of key press. + * @type {number} + */ + this.charCode = 0; + + /** + * Whether control was pressed at time of event. + * @type {boolean} + */ + this.ctrlKey = false; + + /** + * Whether alt was pressed at time of event. + * @type {boolean} + */ + this.altKey = false; + + /** + * Whether shift was pressed at time of event. + * @type {boolean} + */ + this.shiftKey = false; + + /** + * Whether the meta key was pressed at time of event. + * @type {boolean} + */ + this.metaKey = false; + + /** + * History state object, only set for PopState events where it's a copy of the + * state object provided to pushState or replaceState. + * @type {Object} + */ + this.state = null; + + /** + * Whether the default platform modifier key was pressed at time of event. + * (This is control for all platforms except Mac, where it's Meta.) + * @type {boolean} + */ + this.platformModifierKey = false; + + /** + * The browser event object. + * @private {Event} + */ + this.event_ = null; + + if (opt_e) { + this.init(opt_e, opt_currentTarget); + } +}; +goog.inherits(goog.events.BrowserEvent, goog.events.Event); + + +/** + * Normalized button constants for the mouse. + * @enum {number} + */ +goog.events.BrowserEvent.MouseButton = { + LEFT: 0, + MIDDLE: 1, + RIGHT: 2 +}; + + +/** + * Static data for mapping mouse buttons. + * @type {!Array<number>} + */ +goog.events.BrowserEvent.IEButtonMap = [ + 1, // LEFT + 4, // MIDDLE + 2 // RIGHT +]; + + +/** + * Accepts a browser event object and creates a patched, cross browser event + * object. + * @param {Event} e Browser event object. + * @param {EventTarget=} opt_currentTarget Current target for event. + */ +goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) { + var type = this.type = e.type; + + // TODO(nicksantos): Change this.target to type EventTarget. + this.target = /** @type {Node} */ (e.target) || e.srcElement; + + // TODO(nicksantos): Change this.currentTarget to type EventTarget. + this.currentTarget = /** @type {Node} */ (opt_currentTarget); + + var relatedTarget = /** @type {Node} */ (e.relatedTarget); + if (relatedTarget) { + // There's a bug in FireFox where sometimes, relatedTarget will be a + // chrome element, and accessing any property of it will get a permission + // denied exception. See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=497780 + if (goog.userAgent.GECKO) { + if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) { + relatedTarget = null; + } + } + // TODO(arv): Use goog.events.EventType when it has been refactored into its + // own file. + } else if (type == goog.events.EventType.MOUSEOVER) { + relatedTarget = e.fromElement; + } else if (type == goog.events.EventType.MOUSEOUT) { + relatedTarget = e.toElement; + } + + this.relatedTarget = relatedTarget; + + // Webkit emits a lame warning whenever layerX/layerY is accessed. + // http://code.google.com/p/chromium/issues/detail?id=101733 + this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ? + e.offsetX : e.layerX; + this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ? + e.offsetY : e.layerY; + + this.clientX = e.clientX !== undefined ? e.clientX : e.pageX; + this.clientY = e.clientY !== undefined ? e.clientY : e.pageY; + this.screenX = e.screenX || 0; + this.screenY = e.screenY || 0; + + this.button = e.button; + + this.keyCode = e.keyCode || 0; + this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0); + this.ctrlKey = e.ctrlKey; + this.altKey = e.altKey; + this.shiftKey = e.shiftKey; + this.metaKey = e.metaKey; + this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey; + this.state = e.state; + this.event_ = e; + if (e.defaultPrevented) { + this.preventDefault(); + } +}; + + +/** + * Tests to see which button was pressed during the event. This is really only + * useful in IE and Gecko browsers. And in IE, it's only useful for + * mousedown/mouseup events, because click only fires for the left mouse button. + * + * Safari 2 only reports the left button being clicked, and uses the value '1' + * instead of 0. Opera only reports a mousedown event for the middle button, and + * no mouse events for the right button. Opera has default behavior for left and + * middle click that can only be overridden via a configuration setting. + * + * There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html. + * + * @param {goog.events.BrowserEvent.MouseButton} button The button + * to test for. + * @return {boolean} True if button was pressed. + */ +goog.events.BrowserEvent.prototype.isButton = function(button) { + if (!goog.events.BrowserFeature.HAS_W3C_BUTTON) { + if (this.type == 'click') { + return button == goog.events.BrowserEvent.MouseButton.LEFT; + } else { + return !!(this.event_.button & + goog.events.BrowserEvent.IEButtonMap[button]); + } + } else { + return this.event_.button == button; + } +}; + + +/** + * Whether this has an "action"-producing mouse button. + * + * By definition, this includes left-click on windows/linux, and left-click + * without the ctrl key on Macs. + * + * @return {boolean} The result. + */ +goog.events.BrowserEvent.prototype.isMouseActionButton = function() { + // Webkit does not ctrl+click to be a right-click, so we + // normalize it to behave like Gecko and Opera. + return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) && + !(goog.userAgent.WEBKIT && goog.userAgent.MAC && this.ctrlKey); +}; + + +/** + * @override + */ +goog.events.BrowserEvent.prototype.stopPropagation = function() { + goog.events.BrowserEvent.superClass_.stopPropagation.call(this); + if (this.event_.stopPropagation) { + this.event_.stopPropagation(); + } else { + this.event_.cancelBubble = true; + } +}; + + +/** + * @override + */ +goog.events.BrowserEvent.prototype.preventDefault = function() { + goog.events.BrowserEvent.superClass_.preventDefault.call(this); + var be = this.event_; + if (!be.preventDefault) { + be.returnValue = false; + if (goog.events.BrowserFeature.SET_KEY_CODE_TO_PREVENT_DEFAULT) { + /** @preserveTry */ + try { + // Most keys can be prevented using returnValue. Some special keys + // require setting the keyCode to -1 as well: + // + // In IE7: + // F3, F5, F10, F11, Ctrl+P, Crtl+O, Ctrl+F (these are taken from IE6) + // + // In IE8: + // Ctrl+P, Crtl+O, Ctrl+F (F1-F12 cannot be stopped through the event) + // + // We therefore do this for all function keys as well as when Ctrl key + // is pressed. + var VK_F1 = 112; + var VK_F12 = 123; + if (be.ctrlKey || be.keyCode >= VK_F1 && be.keyCode <= VK_F12) { + be.keyCode = -1; + } + } catch (ex) { + // IE throws an 'access denied' exception when trying to change + // keyCode in some situations (e.g. srcElement is input[type=file], + // or srcElement is an anchor tag rewritten by parent's innerHTML). + // Do nothing in this case. + } + } + } else { + be.preventDefault(); + } +}; + + +/** + * @return {Event} The underlying browser event object. + */ +goog.events.BrowserEvent.prototype.getBrowserEvent = function() { + return this.event_; +};
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/browserfeature3.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/browserfeature3.js b/externs/GCL/externs/goog/events/browserfeature3.js new file mode 100644 index 0000000..61b9d60 --- /dev/null +++ b/externs/GCL/externs/goog/events/browserfeature3.js @@ -0,0 +1,85 @@ +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// 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. + +/** + * @fileoverview Browser capability checks for the events package. + * + */ + + +goog.provide('goog.events.BrowserFeature'); + +goog.require('goog.userAgent'); + + +/** + * Enum of browser capabilities. + * @enum {boolean} + */ +goog.events.BrowserFeature = { + /** + * Whether the button attribute of the event is W3C compliant. False in + * Internet Explorer prior to version 9; document-version dependent. + */ + HAS_W3C_BUTTON: !goog.userAgent.IE || + goog.userAgent.isDocumentModeOrHigher(9), + + /** + * Whether the browser supports full W3C event model. + */ + HAS_W3C_EVENT_SUPPORT: !goog.userAgent.IE || + goog.userAgent.isDocumentModeOrHigher(9), + + /** + * To prevent default in IE7-8 for certain keydown events we need set the + * keyCode to -1. + */ + SET_KEY_CODE_TO_PREVENT_DEFAULT: goog.userAgent.IE && + !goog.userAgent.isVersionOrHigher('9'), + + /** + * Whether the {@code navigator.onLine} property is supported. + */ + HAS_NAVIGATOR_ONLINE_PROPERTY: !goog.userAgent.WEBKIT || + goog.userAgent.isVersionOrHigher('528'), + + /** + * Whether HTML5 network online/offline events are supported. + */ + HAS_HTML5_NETWORK_EVENT_SUPPORT: + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9b') || + goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8') || + goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('9.5') || + goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('528'), + + /** + * Whether HTML5 network events fire on document.body, or otherwise the + * window. + */ + HTML5_NETWORK_EVENTS_FIRE_ON_BODY: + goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('8') || + goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'), + + /** + * Whether touch is enabled in the browser. + */ + TOUCH_ENABLED: + ('ontouchstart' in goog.global || + !!(goog.global['document'] && + document.documentElement && + 'ontouchstart' in document.documentElement) || + // IE10 uses non-standard touch events, so it has a different check. + !!(goog.global['navigator'] && + goog.global['navigator']['msMaxTouchPoints'])) +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/event.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/event.js b/externs/GCL/externs/goog/events/event.js new file mode 100644 index 0000000..b671289 --- /dev/null +++ b/externs/GCL/externs/goog/events/event.js @@ -0,0 +1,143 @@ +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// 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. + +/** + * @fileoverview A base class for event objects. + * + */ + + +goog.provide('goog.events.Event'); +goog.provide('goog.events.EventLike'); + +/** + * goog.events.Event no longer depends on goog.Disposable. Keep requiring + * goog.Disposable here to not break projects which assume this dependency. + * @suppress {extraRequire} + */ +goog.require('goog.Disposable'); +goog.require('goog.events.EventId'); + + +/** + * A typedef for event like objects that are dispatchable via the + * goog.events.dispatchEvent function. strings are treated as the type for a + * goog.events.Event. Objects are treated as an extension of a new + * goog.events.Event with the type property of the object being used as the type + * of the Event. + * @typedef {string|Object|goog.events.Event|goog.events.EventId} + */ +goog.events.EventLike; + + + +/** + * A base class for event objects, so that they can support preventDefault and + * stopPropagation. + * + * @param {string|!goog.events.EventId} type Event Type. + * @param {Object=} opt_target Reference to the object that is the target of + * this event. It has to implement the {@code EventTarget} interface + * declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}. + * @constructor + */ +goog.events.Event = function(type, opt_target) { + /** + * Event type. + * @type {string} + */ + this.type = type instanceof goog.events.EventId ? String(type) : type; + + /** + * TODO(tbreisacher): The type should probably be + * EventTarget|goog.events.EventTarget. + * + * Target of the event. + * @type {Object|undefined} + */ + this.target = opt_target; + + /** + * Object that had the listener attached. + * @type {Object|undefined} + */ + this.currentTarget = this.target; + + /** + * Whether to cancel the event in internal capture/bubble processing for IE. + * @type {boolean} + * @public + * @suppress {underscore|visibility} Technically public, but referencing this + * outside this package is strongly discouraged. + */ + this.propagationStopped_ = false; + + /** + * Whether the default action has been prevented. + * This is a property to match the W3C specification at + * {@link http://www.w3.org/TR/DOM-Level-3-Events/ + * #events-event-type-defaultPrevented}. + * Must be treated as read-only outside the class. + * @type {boolean} + */ + this.defaultPrevented = false; + + /** + * Return value for in internal capture/bubble processing for IE. + * @type {boolean} + * @public + * @suppress {underscore|visibility} Technically public, but referencing this + * outside this package is strongly discouraged. + */ + this.returnValue_ = true; +}; + + +/** + * Stops event propagation. + */ +goog.events.Event.prototype.stopPropagation = function() { + this.propagationStopped_ = true; +}; + + +/** + * Prevents the default action, for example a link redirecting to a url. + */ +goog.events.Event.prototype.preventDefault = function() { + this.defaultPrevented = true; + this.returnValue_ = false; +}; + + +/** + * Stops the propagation of the event. It is equivalent to + * {@code e.stopPropagation()}, but can be used as the callback argument of + * {@link goog.events.listen} without declaring another function. + * @param {!goog.events.Event} e An event. + */ +goog.events.Event.stopPropagation = function(e) { + e.stopPropagation(); +}; + + +/** + * Prevents the default action. It is equivalent to + * {@code e.preventDefault()}, but can be used as the callback argument of + * {@link goog.events.listen} without declaring another function. + * @param {!goog.events.Event} e An event. + */ +goog.events.Event.preventDefault = function(e) { + e.preventDefault(); +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventhandler.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/eventhandler.js b/externs/GCL/externs/goog/events/eventhandler.js new file mode 100644 index 0000000..16b1ad0 --- /dev/null +++ b/externs/GCL/externs/goog/events/eventhandler.js @@ -0,0 +1,459 @@ +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// 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. + +/** + * @fileoverview Class to create objects which want to handle multiple events + * and have their listeners easily cleaned up via a dispose method. + * + * Example: + * <pre> + * function Something() { + * Something.base(this); + * + * ... set up object ... + * + * // Add event listeners + * this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar); + * this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand); + * this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse); + * this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover); + * this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover); + * } + * goog.inherits(Something, goog.events.EventHandler); + * + * Something.prototype.disposeInternal = function() { + * Something.base(this, 'disposeInternal'); + * goog.dom.removeNode(this.container); + * }; + * + * + * // Then elsewhere: + * + * var activeSomething = null; + * function openSomething() { + * activeSomething = new Something(); + * } + * + * function closeSomething() { + * if (activeSomething) { + * activeSomething.dispose(); // Remove event listeners + * activeSomething = null; + * } + * } + * </pre> + * + */ + +goog.provide('goog.events.EventHandler'); + +goog.require('goog.Disposable'); +goog.require('goog.events'); +goog.require('goog.object'); + +goog.forwardDeclare('goog.events.EventWrapper'); + + + +/** + * Super class for objects that want to easily manage a number of event + * listeners. It allows a short cut to listen and also provides a quick way + * to remove all events listeners belonging to this object. + * @param {SCOPE=} opt_scope Object in whose scope to call the listeners. + * @constructor + * @extends {goog.Disposable} + * @template SCOPE + */ +goog.events.EventHandler = function(opt_scope) { + goog.Disposable.call(this); + // TODO(mknichel): Rename this to this.scope_ and fix the classes in google3 + // that access this private variable. :( + this.handler_ = opt_scope; + + /** + * Keys for events that are being listened to. + * @type {!Object<!goog.events.Key>} + * @private + */ + this.keys_ = {}; +}; +goog.inherits(goog.events.EventHandler, goog.Disposable); + + +/** + * Utility array used to unify the cases of listening for an array of types + * and listening for a single event, without using recursion or allocating + * an array each time. + * @type {!Array<string>} + * @const + * @private + */ +goog.events.EventHandler.typeArray_ = []; + + +/** + * Listen to an event on a Listenable. If the function is omitted then the + * EventHandler's handleEvent method will be used. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} + * opt_fn Optional callback function to be used as the listener or an object + * with handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + */ +goog.events.EventHandler.prototype.listen = function( + src, type, opt_fn, opt_capture) { + return this.listen_(src, type, opt_fn, opt_capture); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted then the + * EventHandler's handleEvent method will be used. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| + * null|undefined} fn Optional callback function to be used as the + * listener or an object with handleEvent function. + * @param {boolean|undefined} capture Optional whether to use capture phase. + * @param {T} scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template T,EVENTOBJ + */ +goog.events.EventHandler.prototype.listenWithScope = function( + src, type, fn, capture, scope) { + // TODO(mknichel): Deprecate this function. + return this.listen_(src, type, fn, capture, scope); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted then the + * EventHandler's handleEvent method will be used. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @param {Object=} opt_scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + * @private + */ +goog.events.EventHandler.prototype.listen_ = function(src, type, opt_fn, + opt_capture, + opt_scope) { + if (!goog.isArray(type)) { + if (type) { + goog.events.EventHandler.typeArray_[0] = type.toString(); + } + type = goog.events.EventHandler.typeArray_; + } + for (var i = 0; i < type.length; i++) { + var listenerObj = goog.events.listen( + src, type[i], opt_fn || this.handleEvent, + opt_capture || false, + opt_scope || this.handler_ || this); + + if (!listenerObj) { + // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT + // (goog.events.CaptureSimulationMode) in IE8-, it will return null + // value. + return this; + } + + var key = listenerObj.key; + this.keys_[key] = listenerObj; + } + + return this; +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted, then the + * EventHandler's handleEvent method will be used. After the event has fired the + * event listener is removed from the target. If an array of event types is + * provided, each event type will be listened to once. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + */ +goog.events.EventHandler.prototype.listenOnce = function( + src, type, opt_fn, opt_capture) { + return this.listenOnce_(src, type, opt_fn, opt_capture); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted, then the + * EventHandler's handleEvent method will be used. After the event has fired the + * event listener is removed from the target. If an array of event types is + * provided, each event type will be listened to once. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| + * null|undefined} fn Optional callback function to be used as the + * listener or an object with handleEvent function. + * @param {boolean|undefined} capture Optional whether to use capture phase. + * @param {T} scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template T,EVENTOBJ + */ +goog.events.EventHandler.prototype.listenOnceWithScope = function( + src, type, fn, capture, scope) { + // TODO(mknichel): Deprecate this function. + return this.listenOnce_(src, type, fn, capture, scope); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted, then the + * EventHandler's handleEvent method will be used. After the event has fired + * the event listener is removed from the target. If an array of event types is + * provided, each event type will be listened to once. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @param {Object=} opt_scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + * @private + */ +goog.events.EventHandler.prototype.listenOnce_ = function( + src, type, opt_fn, opt_capture, opt_scope) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + this.listenOnce_(src, type[i], opt_fn, opt_capture, opt_scope); + } + } else { + var listenerObj = goog.events.listenOnce( + src, type, opt_fn || this.handleEvent, opt_capture, + opt_scope || this.handler_ || this); + if (!listenerObj) { + // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT + // (goog.events.CaptureSimulationMode) in IE8-, it will return null + // value. + return this; + } + + var key = listenerObj.key; + this.keys_[key] = listenerObj; + } + + return this; +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.EventTarget}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.EventTarget} src The node to listen to + * events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener + * Callback method, or an object with a handleEvent function. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + */ +goog.events.EventHandler.prototype.listenWithWrapper = function( + src, wrapper, listener, opt_capt) { + // TODO(mknichel): Remove the opt_scope from this function and then + // templatize it. + return this.listenWithWrapper_(src, wrapper, listener, opt_capt); +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.EventTarget}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.EventTarget} src The node to listen to + * events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null} + * listener Optional callback function to be used as the + * listener or an object with handleEvent function. + * @param {boolean|undefined} capture Optional whether to use capture phase. + * @param {T} scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template T + */ +goog.events.EventHandler.prototype.listenWithWrapperAndScope = function( + src, wrapper, listener, capture, scope) { + // TODO(mknichel): Deprecate this function. + return this.listenWithWrapper_(src, wrapper, listener, capture, scope); +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.EventTarget}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.EventTarget} src The node to listen to + * events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback + * method, or an object with a handleEvent function. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {Object=} opt_scope Element in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @private + */ +goog.events.EventHandler.prototype.listenWithWrapper_ = function( + src, wrapper, listener, opt_capt, opt_scope) { + wrapper.listen(src, listener, opt_capt, opt_scope || this.handler_ || this, + this); + return this; +}; + + +/** + * @return {number} Number of listeners registered by this handler. + */ +goog.events.EventHandler.prototype.getListenerCount = function() { + var count = 0; + for (var key in this.keys_) { + if (Object.prototype.hasOwnProperty.call(this.keys_, key)) { + count++; + } + } + return count; +}; + + +/** + * Unlistens on an event. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types to unlisten to. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @param {Object=} opt_scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler} This object, allowing for chaining of + * calls. + * @template EVENTOBJ + */ +goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn, + opt_capture, + opt_scope) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + this.unlisten(src, type[i], opt_fn, opt_capture, opt_scope); + } + } else { + var listener = goog.events.getListener(src, type, + opt_fn || this.handleEvent, + opt_capture, opt_scope || this.handler_ || this); + + if (listener) { + goog.events.unlistenByKey(listener); + delete this.keys_[listener.key]; + } + } + + return this; +}; + + +/** + * Removes an event listener which was added with listenWithWrapper(). + * + * @param {EventTarget|goog.events.EventTarget} src The target to stop + * listening to events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener The + * listener function to remove. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase of the + * event. + * @param {Object=} opt_scope Element in whose scope to call the listener. + * @return {!goog.events.EventHandler} This object, allowing for chaining of + * calls. + */ +goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper, + listener, opt_capt, opt_scope) { + wrapper.unlisten(src, listener, opt_capt, + opt_scope || this.handler_ || this, this); + return this; +}; + + +/** + * Unlistens to all events. + */ +goog.events.EventHandler.prototype.removeAll = function() { + goog.object.forEach(this.keys_, goog.events.unlistenByKey); + this.keys_ = {}; +}; + + +/** + * Disposes of this EventHandler and removes all listeners that it registered. + * @override + * @protected + */ +goog.events.EventHandler.prototype.disposeInternal = function() { + goog.events.EventHandler.superClass_.disposeInternal.call(this); + this.removeAll(); +}; + + +/** + * Default event handler + * @param {goog.events.Event} e Event object. + */ +goog.events.EventHandler.prototype.handleEvent = function(e) { + throw Error('EventHandler.handleEvent not implemented'); +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventid.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/eventid.js b/externs/GCL/externs/goog/events/eventid.js new file mode 100644 index 0000000..9a4822e --- /dev/null +++ b/externs/GCL/externs/goog/events/eventid.js @@ -0,0 +1,47 @@ +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// 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('goog.events.EventId'); + + + +/** + * A templated class that is used when registering for events. Typical usage: + * <code> + * /** @type {goog.events.EventId<MyEventObj>} + * var myEventId = new goog.events.EventId( + * goog.events.getUniqueId(('someEvent')); + * + * // No need to cast or declare here since the compiler knows the correct + * // type of 'evt' (MyEventObj). + * something.listen(myEventId, function(evt) {}); + * </code> + * + * @param {string} eventId + * @template T + * @constructor + * @struct + * @final + */ +goog.events.EventId = function(eventId) { + /** @const */ this.id = eventId; +}; + + +/** + * @override + */ +goog.events.EventId.prototype.toString = function() { + return this.id; +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/events.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/events.js b/externs/GCL/externs/goog/events/events.js new file mode 100644 index 0000000..39cc405 --- /dev/null +++ b/externs/GCL/externs/goog/events/events.js @@ -0,0 +1,983 @@ +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// 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. + +/** + * @fileoverview An event manager for both native browser event + * targets and custom JavaScript event targets + * ({@code goog.events.Listenable}). This provides an abstraction + * over browsers' event systems. + * + * It also provides a simulation of W3C event model's capture phase in + * Internet Explorer (IE 8 and below). Caveat: the simulation does not + * interact well with listeners registered directly on the elements + * (bypassing goog.events) or even with listeners registered via + * goog.events in a separate JS binary. In these cases, we provide + * no ordering guarantees. + * + * The listeners will receive a "patched" event object. Such event object + * contains normalized values for certain event properties that differs in + * different browsers. + * + * Example usage: + * <pre> + * goog.events.listen(myNode, 'click', function(e) { alert('woo') }); + * goog.events.listen(myNode, 'mouseover', mouseHandler, true); + * goog.events.unlisten(myNode, 'mouseover', mouseHandler, true); + * goog.events.removeAll(myNode); + * </pre> + * + * in IE and event object patching] + * @author [email protected] (Erik Arvidsson) + * + * @see ../demos/events.html + * @see ../demos/event-propagation.html + * @see ../demos/stopevent.html + */ + +// IMPLEMENTATION NOTES: +// goog.events stores an auxiliary data structure on each EventTarget +// source being listened on. This allows us to take advantage of GC, +// having the data structure GC'd when the EventTarget is GC'd. This +// GC behavior is equivalent to using W3C DOM Events directly. + +goog.provide('goog.events'); +goog.provide('goog.events.CaptureSimulationMode'); +goog.provide('goog.events.Key'); +goog.provide('goog.events.ListenableType'); + +goog.require('goog.asserts'); +goog.require('goog.debug.entryPointRegistry'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.BrowserFeature'); +goog.require('goog.events.Listenable'); +goog.require('goog.events.ListenerMap'); + +goog.forwardDeclare('goog.debug.ErrorHandler'); +goog.forwardDeclare('goog.events.EventWrapper'); + + +/** + * @typedef {number|goog.events.ListenableKey} + */ +goog.events.Key; + + +/** + * @typedef {EventTarget|goog.events.Listenable} + */ +goog.events.ListenableType; + + +/** + * Property name on a native event target for the listener map + * associated with the event target. + * @private @const {string} + */ +goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0); + + +/** + * String used to prepend to IE event types. + * @const + * @private + */ +goog.events.onString_ = 'on'; + + +/** + * Map of computed "on<eventname>" strings for IE event types. Caching + * this removes an extra object allocation in goog.events.listen which + * improves IE6 performance. + * @const + * @dict + * @private + */ +goog.events.onStringMap_ = {}; + + +/** + * @enum {number} Different capture simulation mode for IE8-. + */ +goog.events.CaptureSimulationMode = { + /** + * Does not perform capture simulation. Will asserts in IE8- when you + * add capture listeners. + */ + OFF_AND_FAIL: 0, + + /** + * Does not perform capture simulation, silently ignore capture + * listeners. + */ + OFF_AND_SILENT: 1, + + /** + * Performs capture simulation. + */ + ON: 2 +}; + + +/** + * @define {number} The capture simulation mode for IE8-. By default, + * this is ON. + */ +goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2); + + +/** + * Estimated count of total native listeners. + * @private {number} + */ +goog.events.listenerCountEstimate_ = 0; + + +/** + * Adds an event listener for a specific event on a native event + * target (such as a DOM element) or an object that has implemented + * {@link goog.events.Listenable}. A listener can only be added once + * to an object and if it is added again the key for the listener is + * returned. Note that if the existing listener is a one-off listener + * (registered via listenOnce), it will no longer be a one-off + * listener after a call to listen(). + * + * @param {EventTarget|goog.events.Listenable} src The node to listen + * to events on. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} + * listener Callback method, or an object with a handleEvent function. + * WARNING: passing an Object is now softly deprecated. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {T=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.Key} Unique key for the listener. + * @template T,EVENTOBJ + */ +goog.events.listen = function(src, type, listener, opt_capt, opt_handler) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + goog.events.listen(src, type[i], listener, opt_capt, opt_handler); + } + return null; + } + + listener = goog.events.wrapListener(listener); + if (goog.events.Listenable.isImplementedBy(src)) { + return src.listen( + /** @type {string|!goog.events.EventId} */ (type), + listener, opt_capt, opt_handler); + } else { + return goog.events.listen_( + /** @type {!EventTarget} */ (src), + /** @type {string|!goog.events.EventId} */ (type), + listener, /* callOnce */ false, opt_capt, opt_handler); + } +}; + + +/** + * Adds an event listener for a specific event on a native event + * target. A listener can only be added once to an object and if it + * is added again the key for the listener is returned. + * + * Note that a one-off listener will not change an existing listener, + * if any. On the other hand a normal listener will change existing + * one-off listener to become a normal listener. + * + * @param {EventTarget} src The node to listen to events on. + * @param {string|!goog.events.EventId} type Event type. + * @param {!Function} listener Callback function. + * @param {boolean} callOnce Whether the listener is a one-off + * listener or otherwise. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {Object=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.ListenableKey} Unique key for the listener. + * @private + */ +goog.events.listen_ = function( + src, type, listener, callOnce, opt_capt, opt_handler) { + if (!type) { + throw Error('Invalid event type'); + } + + var capture = !!opt_capt; + if (capture && !goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { + if (goog.events.CAPTURE_SIMULATION_MODE == + goog.events.CaptureSimulationMode.OFF_AND_FAIL) { + goog.asserts.fail('Can not register capture listener in IE8-.'); + return null; + } else if (goog.events.CAPTURE_SIMULATION_MODE == + goog.events.CaptureSimulationMode.OFF_AND_SILENT) { + return null; + } + } + + var listenerMap = goog.events.getListenerMap_(src); + if (!listenerMap) { + src[goog.events.LISTENER_MAP_PROP_] = listenerMap = + new goog.events.ListenerMap(src); + } + + var listenerObj = listenerMap.add( + type, listener, callOnce, opt_capt, opt_handler); + + // If the listenerObj already has a proxy, it has been set up + // previously. We simply return. + if (listenerObj.proxy) { + return listenerObj; + } + + var proxy = goog.events.getProxy(); + listenerObj.proxy = proxy; + + proxy.src = src; + proxy.listener = listenerObj; + + // Attach the proxy through the browser's API + if (src.addEventListener) { + src.addEventListener(type.toString(), proxy, capture); + } else { + // The else above used to be else if (src.attachEvent) and then there was + // another else statement that threw an exception warning the developer + // they made a mistake. This resulted in an extra object allocation in IE6 + // due to a wrapper object that had to be implemented around the element + // and so was removed. + src.attachEvent(goog.events.getOnString_(type.toString()), proxy); + } + + goog.events.listenerCountEstimate_++; + return listenerObj; +}; + + +/** + * Helper function for returning a proxy function. + * @return {!Function} A new or reused function object. + */ +goog.events.getProxy = function() { + var proxyCallbackFunction = goog.events.handleBrowserEvent_; + // Use a local var f to prevent one allocation. + var f = goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT ? + function(eventObject) { + return proxyCallbackFunction.call(f.src, f.listener, eventObject); + } : + function(eventObject) { + var v = proxyCallbackFunction.call(f.src, f.listener, eventObject); + // NOTE(chrishenry): In IE, we hack in a capture phase. However, if + // there is inline event handler which tries to prevent default (for + // example <a href="..." onclick="return false">...</a>) in a + // descendant element, the prevent default will be overridden + // by this listener if this listener were to return true. Hence, we + // return undefined. + if (!v) return v; + }; + return f; +}; + + +/** + * Adds an event listener for a specific event on a native event + * target (such as a DOM element) or an object that has implemented + * {@link goog.events.Listenable}. After the event has fired the event + * listener is removed from the target. + * + * If an existing listener already exists, listenOnce will do + * nothing. In particular, if the listener was previously registered + * via listen(), listenOnce() will not turn the listener into a + * one-off listener. Similarly, if there is already an existing + * one-off listener, listenOnce does not modify the listeners (it is + * still a once listener). + * + * @param {EventTarget|goog.events.Listenable} src The node to listen + * to events on. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} + * listener Callback method. + * @param {boolean=} opt_capt Fire in capture phase?. + * @param {T=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.Key} Unique key for the listener. + * @template T,EVENTOBJ + */ +goog.events.listenOnce = function(src, type, listener, opt_capt, opt_handler) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + goog.events.listenOnce(src, type[i], listener, opt_capt, opt_handler); + } + return null; + } + + listener = goog.events.wrapListener(listener); + if (goog.events.Listenable.isImplementedBy(src)) { + return src.listenOnce( + /** @type {string|!goog.events.EventId} */ (type), + listener, opt_capt, opt_handler); + } else { + return goog.events.listen_( + /** @type {!EventTarget} */ (src), + /** @type {string|!goog.events.EventId} */ (type), + listener, /* callOnce */ true, opt_capt, opt_handler); + } +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.Listenable}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.Listenable} src The target to + * listen to events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener + * Callback method, or an object with a handleEvent function. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {T=} opt_handler Element in whose scope to call the listener. + * @template T + */ +goog.events.listenWithWrapper = function(src, wrapper, listener, opt_capt, + opt_handler) { + wrapper.listen(src, listener, opt_capt, opt_handler); +}; + + +/** + * Removes an event listener which was added with listen(). + * + * @param {EventTarget|goog.events.Listenable} src The target to stop + * listening to events on. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types to unlisten to. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener The + * listener function to remove. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase of the + * event. + * @param {Object=} opt_handler Element in whose scope to call the listener. + * @return {?boolean} indicating whether the listener was there to remove. + * @template EVENTOBJ + */ +goog.events.unlisten = function(src, type, listener, opt_capt, opt_handler) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + goog.events.unlisten(src, type[i], listener, opt_capt, opt_handler); + } + return null; + } + + listener = goog.events.wrapListener(listener); + if (goog.events.Listenable.isImplementedBy(src)) { + return src.unlisten( + /** @type {string|!goog.events.EventId} */ (type), + listener, opt_capt, opt_handler); + } + + if (!src) { + // TODO(chrishenry): We should tighten the API to only accept + // non-null objects, or add an assertion here. + return false; + } + + var capture = !!opt_capt; + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (src)); + if (listenerMap) { + var listenerObj = listenerMap.getListener( + /** @type {string|!goog.events.EventId} */ (type), + listener, capture, opt_handler); + if (listenerObj) { + return goog.events.unlistenByKey(listenerObj); + } + } + + return false; +}; + + +/** + * Removes an event listener which was added with listen() by the key + * returned by listen(). + * + * @param {goog.events.Key} key The key returned by listen() for this + * event listener. + * @return {boolean} indicating whether the listener was there to remove. + */ +goog.events.unlistenByKey = function(key) { + // TODO(chrishenry): Remove this check when tests that rely on this + // are fixed. + if (goog.isNumber(key)) { + return false; + } + + var listener = /** @type {goog.events.ListenableKey} */ (key); + if (!listener || listener.removed) { + return false; + } + + var src = listener.src; + if (goog.events.Listenable.isImplementedBy(src)) { + return src.unlistenByKey(listener); + } + + var type = listener.type; + var proxy = listener.proxy; + if (src.removeEventListener) { + src.removeEventListener(type, proxy, listener.capture); + } else if (src.detachEvent) { + src.detachEvent(goog.events.getOnString_(type), proxy); + } + goog.events.listenerCountEstimate_--; + + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (src)); + // TODO(chrishenry): Try to remove this conditional and execute the + // first branch always. This should be safe. + if (listenerMap) { + listenerMap.removeByKey(listener); + if (listenerMap.getTypeCount() == 0) { + // Null the src, just because this is simple to do (and useful + // for IE <= 7). + listenerMap.src = null; + // We don't use delete here because IE does not allow delete + // on a window object. + src[goog.events.LISTENER_MAP_PROP_] = null; + } + } else { + listener.markAsRemoved(); + } + + return true; +}; + + +/** + * Removes an event listener which was added with listenWithWrapper(). + * + * @param {EventTarget|goog.events.Listenable} src The target to stop + * listening to events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener The + * listener function to remove. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase of the + * event. + * @param {Object=} opt_handler Element in whose scope to call the listener. + */ +goog.events.unlistenWithWrapper = function(src, wrapper, listener, opt_capt, + opt_handler) { + wrapper.unlisten(src, listener, opt_capt, opt_handler); +}; + + +/** + * Removes all listeners from an object. You can also optionally + * remove listeners of a particular type. + * + * @param {Object|undefined} obj Object to remove listeners from. Must be an + * EventTarget or a goog.events.Listenable. + * @param {string|!goog.events.EventId=} opt_type Type of event to remove. + * Default is all types. + * @return {number} Number of listeners removed. + */ +goog.events.removeAll = function(obj, opt_type) { + // TODO(chrishenry): Change the type of obj to + // (!EventTarget|!goog.events.Listenable). + + if (!obj) { + return 0; + } + + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.removeAllListeners(opt_type); + } + + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (obj)); + if (!listenerMap) { + return 0; + } + + var count = 0; + var typeStr = opt_type && opt_type.toString(); + for (var type in listenerMap.listeners) { + if (!typeStr || type == typeStr) { + // Clone so that we don't need to worry about unlistenByKey + // changing the content of the ListenerMap. + var listeners = listenerMap.listeners[type].concat(); + for (var i = 0; i < listeners.length; ++i) { + if (goog.events.unlistenByKey(listeners[i])) { + ++count; + } + } + } + } + return count; +}; + + +/** + * Gets the listeners for a given object, type and capture phase. + * + * @param {Object} obj Object to get listeners for. + * @param {string|!goog.events.EventId} type Event type. + * @param {boolean} capture Capture phase?. + * @return {Array<goog.events.Listener>} Array of listener objects. + */ +goog.events.getListeners = function(obj, type, capture) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.getListeners(type, capture); + } else { + if (!obj) { + // TODO(chrishenry): We should tighten the API to accept + // !EventTarget|goog.events.Listenable, and add an assertion here. + return []; + } + + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (obj)); + return listenerMap ? listenerMap.getListeners(type, capture) : []; + } +}; + + +/** + * Gets the goog.events.Listener for the event or null if no such listener is + * in use. + * + * @param {EventTarget|goog.events.Listenable} src The target from + * which to get listeners. + * @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The + * listener function to get. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the + * capture or bubble phase of the event. + * @param {Object=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.ListenableKey} the found listener or null if not found. + * @template EVENTOBJ + */ +goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) { + // TODO(chrishenry): Change type from ?string to string, or add assertion. + type = /** @type {string} */ (type); + listener = goog.events.wrapListener(listener); + var capture = !!opt_capt; + if (goog.events.Listenable.isImplementedBy(src)) { + return src.getListener(type, listener, capture, opt_handler); + } + + if (!src) { + // TODO(chrishenry): We should tighten the API to only accept + // non-null objects, or add an assertion here. + return null; + } + + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (src)); + if (listenerMap) { + return listenerMap.getListener(type, listener, capture, opt_handler); + } + return null; +}; + + +/** + * Returns whether an event target has any active listeners matching the + * specified signature. If either the type or capture parameters are + * unspecified, the function will match on the remaining criteria. + * + * @param {EventTarget|goog.events.Listenable} obj Target to get + * listeners for. + * @param {string|!goog.events.EventId=} opt_type Event type. + * @param {boolean=} opt_capture Whether to check for capture or bubble-phase + * listeners. + * @return {boolean} Whether an event target has one or more listeners matching + * the requested type and/or capture phase. + */ +goog.events.hasListener = function(obj, opt_type, opt_capture) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.hasListener(opt_type, opt_capture); + } + + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (obj)); + return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture); +}; + + +/** + * Provides a nice string showing the normalized event objects public members + * @param {Object} e Event Object. + * @return {string} String of the public members of the normalized event object. + */ +goog.events.expose = function(e) { + var str = []; + for (var key in e) { + if (e[key] && e[key].id) { + str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')'); + } else { + str.push(key + ' = ' + e[key]); + } + } + return str.join('\n'); +}; + + +/** + * Returns a string with on prepended to the specified type. This is used for IE + * which expects "on" to be prepended. This function caches the string in order + * to avoid extra allocations in steady state. + * @param {string} type Event type. + * @return {string} The type string with 'on' prepended. + * @private + */ +goog.events.getOnString_ = function(type) { + if (type in goog.events.onStringMap_) { + return goog.events.onStringMap_[type]; + } + return goog.events.onStringMap_[type] = goog.events.onString_ + type; +}; + + +/** + * Fires an object's listeners of a particular type and phase + * + * @param {Object} obj Object whose listeners to call. + * @param {string|!goog.events.EventId} type Event type. + * @param {boolean} capture Which event phase. + * @param {Object} eventObject Event object to be passed to listener. + * @return {boolean} True if all listeners returned true else false. + */ +goog.events.fireListeners = function(obj, type, capture, eventObject) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.fireListeners(type, capture, eventObject); + } + + return goog.events.fireListeners_(obj, type, capture, eventObject); +}; + + +/** + * Fires an object's listeners of a particular type and phase. + * @param {Object} obj Object whose listeners to call. + * @param {string|!goog.events.EventId} type Event type. + * @param {boolean} capture Which event phase. + * @param {Object} eventObject Event object to be passed to listener. + * @return {boolean} True if all listeners returned true else false. + * @private + */ +goog.events.fireListeners_ = function(obj, type, capture, eventObject) { + /** @type {boolean} */ + var retval = true; + + var listenerMap = goog.events.getListenerMap_( + /** @type {EventTarget} */ (obj)); + if (listenerMap) { + // TODO(chrishenry): Original code avoids array creation when there + // is no listener, so we do the same. If this optimization turns + // out to be not required, we can replace this with + // listenerMap.getListeners(type, capture) instead, which is simpler. + var listenerArray = listenerMap.listeners[type.toString()]; + if (listenerArray) { + listenerArray = listenerArray.concat(); + for (var i = 0; i < listenerArray.length; i++) { + var listener = listenerArray[i]; + // We might not have a listener if the listener was removed. + if (listener && listener.capture == capture && !listener.removed) { + var result = goog.events.fireListener(listener, eventObject); + retval = retval && (result !== false); + } + } + } + } + return retval; +}; + + +/** + * Fires a listener with a set of arguments + * + * @param {goog.events.Listener} listener The listener object to call. + * @param {Object} eventObject The event object to pass to the listener. + * @return {boolean} Result of listener. + */ +goog.events.fireListener = function(listener, eventObject) { + var listenerFn = listener.listener; + var listenerHandler = listener.handler || listener.src; + + if (listener.callOnce) { + goog.events.unlistenByKey(listener); + } + return listenerFn.call(listenerHandler, eventObject); +}; + + +/** + * Gets the total number of listeners currently in the system. + * @return {number} Number of listeners. + * @deprecated This returns estimated count, now that Closure no longer + * stores a central listener registry. We still return an estimation + * to keep existing listener-related tests passing. In the near future, + * this function will be removed. + */ +goog.events.getTotalListenerCount = function() { + return goog.events.listenerCountEstimate_; +}; + + +/** + * Dispatches an event (or event like object) and calls all listeners + * listening for events of this type. The type of the event is decided by the + * type property on the event object. + * + * If any of the listeners returns false OR calls preventDefault then this + * function will return false. If one of the capture listeners calls + * stopPropagation, then the bubble listeners won't fire. + * + * @param {goog.events.Listenable} src The event target. + * @param {goog.events.EventLike} e Event object. + * @return {boolean} If anyone called preventDefault on the event object (or + * if any of the handlers returns false) this will also return false. + * If there are no handlers, or if all handlers return true, this returns + * true. + */ +goog.events.dispatchEvent = function(src, e) { + goog.asserts.assert( + goog.events.Listenable.isImplementedBy(src), + 'Can not use goog.events.dispatchEvent with ' + + 'non-goog.events.Listenable instance.'); + return src.dispatchEvent(e); +}; + + +/** + * Installs exception protection for the browser event entry point using the + * given error handler. + * + * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to + * protect the entry point. + */ +goog.events.protectBrowserEventEntryPoint = function(errorHandler) { + goog.events.handleBrowserEvent_ = errorHandler.protectEntryPoint( + goog.events.handleBrowserEvent_); +}; + + +/** + * Handles an event and dispatches it to the correct listeners. This + * function is a proxy for the real listener the user specified. + * + * @param {goog.events.Listener} listener The listener object. + * @param {Event=} opt_evt Optional event object that gets passed in via the + * native event handlers. + * @return {boolean} Result of the event handler. + * @this {EventTarget} The object or Element that fired the event. + * @private + */ +goog.events.handleBrowserEvent_ = function(listener, opt_evt) { + if (listener.removed) { + return true; + } + + // Synthesize event propagation if the browser does not support W3C + // event model. + if (!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { + var ieEvent = opt_evt || + /** @type {Event} */ (goog.getObjectByName('window.event')); + var evt = new goog.events.BrowserEvent(ieEvent, this); + /** @type {boolean} */ + var retval = true; + + if (goog.events.CAPTURE_SIMULATION_MODE == + goog.events.CaptureSimulationMode.ON) { + // If we have not marked this event yet, we should perform capture + // simulation. + if (!goog.events.isMarkedIeEvent_(ieEvent)) { + goog.events.markIeEvent_(ieEvent); + + var ancestors = []; + for (var parent = evt.currentTarget; parent; + parent = parent.parentNode) { + ancestors.push(parent); + } + + // Fire capture listeners. + var type = listener.type; + for (var i = ancestors.length - 1; !evt.propagationStopped_ && i >= 0; + i--) { + evt.currentTarget = ancestors[i]; + var result = goog.events.fireListeners_(ancestors[i], type, true, evt); + retval = retval && result; + } + + // Fire bubble listeners. + // + // We can technically rely on IE to perform bubble event + // propagation. However, it turns out that IE fires events in + // opposite order of attachEvent registration, which broke + // some code and tests that rely on the order. (While W3C DOM + // Level 2 Events TR leaves the event ordering unspecified, + // modern browsers and W3C DOM Level 3 Events Working Draft + // actually specify the order as the registration order.) + for (var i = 0; !evt.propagationStopped_ && i < ancestors.length; i++) { + evt.currentTarget = ancestors[i]; + var result = goog.events.fireListeners_(ancestors[i], type, false, evt); + retval = retval && result; + } + } + } else { + retval = goog.events.fireListener(listener, evt); + } + return retval; + } + + // Otherwise, simply fire the listener. + return goog.events.fireListener( + listener, new goog.events.BrowserEvent(opt_evt, this)); +}; + + +/** + * This is used to mark the IE event object so we do not do the Closure pass + * twice for a bubbling event. + * @param {Event} e The IE browser event. + * @private + */ +goog.events.markIeEvent_ = function(e) { + // Only the keyCode and the returnValue can be changed. We use keyCode for + // non keyboard events. + // event.returnValue is a bit more tricky. It is undefined by default. A + // boolean false prevents the default action. In a window.onbeforeunload and + // the returnValue is non undefined it will be alerted. However, we will only + // modify the returnValue for keyboard events. We can get a problem if non + // closure events sets the keyCode or the returnValue + + var useReturnValue = false; + + if (e.keyCode == 0) { + // We cannot change the keyCode in case that srcElement is input[type=file]. + // We could test that that is the case but that would allocate 3 objects. + // If we use try/catch we will only allocate extra objects in the case of a + // failure. + /** @preserveTry */ + try { + e.keyCode = -1; + return; + } catch (ex) { + useReturnValue = true; + } + } + + if (useReturnValue || + /** @type {boolean|undefined} */ (e.returnValue) == undefined) { + e.returnValue = true; + } +}; + + +/** + * This is used to check if an IE event has already been handled by the Closure + * system so we do not do the Closure pass twice for a bubbling event. + * @param {Event} e The IE browser event. + * @return {boolean} True if the event object has been marked. + * @private + */ +goog.events.isMarkedIeEvent_ = function(e) { + return e.keyCode < 0 || e.returnValue != undefined; +}; + + +/** + * Counter to create unique event ids. + * @private {number} + */ +goog.events.uniqueIdCounter_ = 0; + + +/** + * Creates a unique event id. + * + * @param {string} identifier The identifier. + * @return {string} A unique identifier. + * @idGenerator + */ +goog.events.getUniqueId = function(identifier) { + return identifier + '_' + goog.events.uniqueIdCounter_++; +}; + + +/** + * @param {EventTarget} src The source object. + * @return {goog.events.ListenerMap} A listener map for the given + * source object, or null if none exists. + * @private + */ +goog.events.getListenerMap_ = function(src) { + var listenerMap = src[goog.events.LISTENER_MAP_PROP_]; + // IE serializes the property as well (e.g. when serializing outer + // HTML). So we must check that the value is of the correct type. + return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null; +}; + + +/** + * Expando property for listener function wrapper for Object with + * handleEvent. + * @private @const {string} + */ +goog.events.LISTENER_WRAPPER_PROP_ = '__closure_events_fn_' + + ((Math.random() * 1e9) >>> 0); + + +/** + * @param {Object|Function} listener The listener function or an + * object that contains handleEvent method. + * @return {!Function} Either the original function or a function that + * calls obj.handleEvent. If the same listener is passed to this + * function more than once, the same function is guaranteed to be + * returned. + */ +goog.events.wrapListener = function(listener) { + goog.asserts.assert(listener, 'Listener can not be null.'); + + if (goog.isFunction(listener)) { + return listener; + } + + goog.asserts.assert( + listener.handleEvent, 'An object listener must have handleEvent method.'); + if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) { + listener[goog.events.LISTENER_WRAPPER_PROP_] = + function(e) { return listener.handleEvent(e); }; + } + return listener[goog.events.LISTENER_WRAPPER_PROP_]; +}; + + +// Register the browser event handler as an entry point, so that +// it can be monitored for exception handling, etc. +goog.debug.entryPointRegistry.register( + /** + * @param {function(!Function): !Function} transformer The transforming + * function. + */ + function(transformer) { + goog.events.handleBrowserEvent_ = transformer( + goog.events.handleBrowserEvent_); + }); http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventtarget.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/events/eventtarget.js b/externs/GCL/externs/goog/events/eventtarget.js new file mode 100644 index 0000000..7408c7e --- /dev/null +++ b/externs/GCL/externs/goog/events/eventtarget.js @@ -0,0 +1,394 @@ +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// 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. + +/** + * @fileoverview A disposable implementation of a custom + * listenable/event target. See also: documentation for + * {@code goog.events.Listenable}. + * + * @author [email protected] (Erik Arvidsson) [Original implementation] + * @see ../demos/eventtarget.html + * @see goog.events.Listenable + */ + +goog.provide('goog.events.EventTarget'); + +goog.require('goog.Disposable'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.Listenable'); +goog.require('goog.events.ListenerMap'); +goog.require('goog.object'); + + + +/** + * An implementation of {@code goog.events.Listenable} with full W3C + * EventTarget-like support (capture/bubble mechanism, stopping event + * propagation, preventing default actions). + * + * You may subclass this class to turn your class into a Listenable. + * + * Unless propagation is stopped, an event dispatched by an + * EventTarget will bubble to the parent returned by + * {@code getParentEventTarget}. To set the parent, call + * {@code setParentEventTarget}. Subclasses that don't support + * changing the parent can override the setter to throw an error. + * + * Example usage: + * <pre> + * var source = new goog.events.EventTarget(); + * function handleEvent(e) { + * alert('Type: ' + e.type + '; Target: ' + e.target); + * } + * source.listen('foo', handleEvent); + * // Or: goog.events.listen(source, 'foo', handleEvent); + * ... + * source.dispatchEvent('foo'); // will call handleEvent + * ... + * source.unlisten('foo', handleEvent); + * // Or: goog.events.unlisten(source, 'foo', handleEvent); + * </pre> + * + * @constructor + * @extends {goog.Disposable} + * @implements {goog.events.Listenable} + */ +goog.events.EventTarget = function() { + goog.Disposable.call(this); + + /** + * Maps of event type to an array of listeners. + * @private {!goog.events.ListenerMap} + */ + this.eventTargetListeners_ = new goog.events.ListenerMap(this); + + /** + * The object to use for event.target. Useful when mixing in an + * EventTarget to another object. + * @private {!Object} + */ + this.actualEventTarget_ = this; + + /** + * Parent event target, used during event bubbling. + * + * TODO(chrishenry): Change this to goog.events.Listenable. This + * currently breaks people who expect getParentEventTarget to return + * goog.events.EventTarget. + * + * @private {goog.events.EventTarget} + */ + this.parentEventTarget_ = null; +}; +goog.inherits(goog.events.EventTarget, goog.Disposable); +goog.events.Listenable.addImplementation(goog.events.EventTarget); + + +/** + * An artificial cap on the number of ancestors you can have. This is mainly + * for loop detection. + * @const {number} + * @private + */ +goog.events.EventTarget.MAX_ANCESTORS_ = 1000; + + +/** + * Returns the parent of this event target to use for bubbling. + * + * @return {goog.events.EventTarget} The parent EventTarget or null if + * there is no parent. + * @override + */ +goog.events.EventTarget.prototype.getParentEventTarget = function() { + return this.parentEventTarget_; +}; + + +/** + * Sets the parent of this event target to use for capture/bubble + * mechanism. + * @param {goog.events.EventTarget} parent Parent listenable (null if none). + */ +goog.events.EventTarget.prototype.setParentEventTarget = function(parent) { + this.parentEventTarget_ = parent; +}; + + +/** + * Adds an event listener to the event target. The same handler can only be + * added once per the type. Even if you add the same handler multiple times + * using the same type then it will only be called once when the event is + * dispatched. + * + * @param {string} type The type of the event to listen for. + * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function + * to handle the event. The handler can also be an object that implements + * the handleEvent method which takes the event object as argument. + * @param {boolean=} opt_capture In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase + * of the event. + * @param {Object=} opt_handlerScope Object in whose scope to call + * the listener. + * @deprecated Use {@code #listen} instead, when possible. Otherwise, use + * {@code goog.events.listen} if you are passing Object + * (instead of Function) as handler. + */ +goog.events.EventTarget.prototype.addEventListener = function( + type, handler, opt_capture, opt_handlerScope) { + goog.events.listen(this, type, handler, opt_capture, opt_handlerScope); +}; + + +/** + * Removes an event listener from the event target. The handler must be the + * same object as the one added. If the handler has not been added then + * nothing is done. + * + * @param {string} type The type of the event to listen for. + * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function + * to handle the event. The handler can also be an object that implements + * the handleEvent method which takes the event object as argument. + * @param {boolean=} opt_capture In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase + * of the event. + * @param {Object=} opt_handlerScope Object in whose scope to call + * the listener. + * @deprecated Use {@code #unlisten} instead, when possible. Otherwise, use + * {@code goog.events.unlisten} if you are passing Object + * (instead of Function) as handler. + */ +goog.events.EventTarget.prototype.removeEventListener = function( + type, handler, opt_capture, opt_handlerScope) { + goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope); +}; + + +/** @override */ +goog.events.EventTarget.prototype.dispatchEvent = function(e) { + this.assertInitialized_(); + + var ancestorsTree, ancestor = this.getParentEventTarget(); + if (ancestor) { + ancestorsTree = []; + var ancestorCount = 1; + for (; ancestor; ancestor = ancestor.getParentEventTarget()) { + ancestorsTree.push(ancestor); + goog.asserts.assert( + (++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_), + 'infinite loop'); + } + } + + return goog.events.EventTarget.dispatchEventInternal_( + this.actualEventTarget_, e, ancestorsTree); +}; + + +/** + * Removes listeners from this object. Classes that extend EventTarget may + * need to override this method in order to remove references to DOM Elements + * and additional listeners. + * @override + */ +goog.events.EventTarget.prototype.disposeInternal = function() { + goog.events.EventTarget.superClass_.disposeInternal.call(this); + + this.removeAllListeners(); + this.parentEventTarget_ = null; +}; + + +/** @override */ +goog.events.EventTarget.prototype.listen = function( + type, listener, opt_useCapture, opt_listenerScope) { + this.assertInitialized_(); + return this.eventTargetListeners_.add( + String(type), listener, false /* callOnce */, opt_useCapture, + opt_listenerScope); +}; + + +/** @override */ +goog.events.EventTarget.prototype.listenOnce = function( + type, listener, opt_useCapture, opt_listenerScope) { + return this.eventTargetListeners_.add( + String(type), listener, true /* callOnce */, opt_useCapture, + opt_listenerScope); +}; + + +/** @override */ +goog.events.EventTarget.prototype.unlisten = function( + type, listener, opt_useCapture, opt_listenerScope) { + return this.eventTargetListeners_.remove( + String(type), listener, opt_useCapture, opt_listenerScope); +}; + + +/** @override */ +goog.events.EventTarget.prototype.unlistenByKey = function(key) { + return this.eventTargetListeners_.removeByKey(key); +}; + + +/** @override */ +goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) { + // TODO(chrishenry): Previously, removeAllListeners can be called on + // uninitialized EventTarget, so we preserve that behavior. We + // should remove this when usages that rely on that fact are purged. + if (!this.eventTargetListeners_) { + return 0; + } + return this.eventTargetListeners_.removeAll(opt_type); +}; + + +/** @override */ +goog.events.EventTarget.prototype.fireListeners = function( + type, capture, eventObject) { + // TODO(chrishenry): Original code avoids array creation when there + // is no listener, so we do the same. If this optimization turns + // out to be not required, we can replace this with + // getListeners(type, capture) instead, which is simpler. + var listenerArray = this.eventTargetListeners_.listeners[String(type)]; + if (!listenerArray) { + return true; + } + listenerArray = listenerArray.concat(); + + var rv = true; + for (var i = 0; i < listenerArray.length; ++i) { + var listener = listenerArray[i]; + // We might not have a listener if the listener was removed. + if (listener && !listener.removed && listener.capture == capture) { + var listenerFn = listener.listener; + var listenerHandler = listener.handler || listener.src; + + if (listener.callOnce) { + this.unlistenByKey(listener); + } + rv = listenerFn.call(listenerHandler, eventObject) !== false && rv; + } + } + + return rv && eventObject.returnValue_ != false; +}; + + +/** @override */ +goog.events.EventTarget.prototype.getListeners = function(type, capture) { + return this.eventTargetListeners_.getListeners(String(type), capture); +}; + + +/** @override */ +goog.events.EventTarget.prototype.getListener = function( + type, listener, capture, opt_listenerScope) { + return this.eventTargetListeners_.getListener( + String(type), listener, capture, opt_listenerScope); +}; + + +/** @override */ +goog.events.EventTarget.prototype.hasListener = function( + opt_type, opt_capture) { + var id = goog.isDef(opt_type) ? String(opt_type) : undefined; + return this.eventTargetListeners_.hasListener(id, opt_capture); +}; + + +/** + * Sets the target to be used for {@code event.target} when firing + * event. Mainly used for testing. For example, see + * {@code goog.testing.events.mixinListenable}. + * @param {!Object} target The target. + */ +goog.events.EventTarget.prototype.setTargetForTesting = function(target) { + this.actualEventTarget_ = target; +}; + + +/** + * Asserts that the event target instance is initialized properly. + * @private + */ +goog.events.EventTarget.prototype.assertInitialized_ = function() { + goog.asserts.assert( + this.eventTargetListeners_, + 'Event target is not initialized. Did you call the superclass ' + + '(goog.events.EventTarget) constructor?'); +}; + + +/** + * Dispatches the given event on the ancestorsTree. + * + * @param {!Object} target The target to dispatch on. + * @param {goog.events.Event|Object|string} e The event object. + * @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors + * tree of the target, in reverse order from the closest ancestor + * to the root event target. May be null if the target has no ancestor. + * @return {boolean} If anyone called preventDefault on the event object (or + * if any of the listeners returns false) this will also return false. + * @private + */ +goog.events.EventTarget.dispatchEventInternal_ = function( + target, e, opt_ancestorsTree) { + var type = e.type || /** @type {string} */ (e); + + // If accepting a string or object, create a custom event object so that + // preventDefault and stopPropagation work with the event. + if (goog.isString(e)) { + e = new goog.events.Event(e, target); + } else if (!(e instanceof goog.events.Event)) { + var oldEvent = e; + e = new goog.events.Event(type, target); + goog.object.extend(e, oldEvent); + } else { + e.target = e.target || target; + } + + var rv = true, currentTarget; + + // Executes all capture listeners on the ancestors, if any. + if (opt_ancestorsTree) { + for (var i = opt_ancestorsTree.length - 1; !e.propagationStopped_ && i >= 0; + i--) { + currentTarget = e.currentTarget = opt_ancestorsTree[i]; + rv = currentTarget.fireListeners(type, true, e) && rv; + } + } + + // Executes capture and bubble listeners on the target. + if (!e.propagationStopped_) { + currentTarget = e.currentTarget = target; + rv = currentTarget.fireListeners(type, true, e) && rv; + if (!e.propagationStopped_) { + rv = currentTarget.fireListeners(type, false, e) && rv; + } + } + + // Executes all bubble listeners on the ancestors, if any. + if (opt_ancestorsTree) { + for (i = 0; !e.propagationStopped_ && i < opt_ancestorsTree.length; i++) { + currentTarget = e.currentTarget = opt_ancestorsTree[i]; + rv = currentTarget.fireListeners(type, false, e) && rv; + } + } + + return rv; +};
