From 16cfbd19157df76e7296dddb287412f1099feb33 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Fri, 20 May 2022 13:37:43 -0600 Subject: Move static assets to within srv --- .../http/static/viz/1/goog/events/browserevent.js | 402 +++++++++ .../static/viz/1/goog/events/browserfeature.js | 84 ++ srv/src/http/static/viz/1/goog/events/event.js | 145 +++ srv/src/http/static/viz/1/goog/events/eventid.js | 46 + srv/src/http/static/viz/1/goog/events/events.js | 989 +++++++++++++++++++++ srv/src/http/static/viz/1/goog/events/eventtype.js | 239 +++++ .../http/static/viz/1/goog/events/listenable.js | 338 +++++++ srv/src/http/static/viz/1/goog/events/listener.js | 131 +++ .../http/static/viz/1/goog/events/listenermap.js | 306 +++++++ 9 files changed, 2680 insertions(+) create mode 100644 srv/src/http/static/viz/1/goog/events/browserevent.js create mode 100644 srv/src/http/static/viz/1/goog/events/browserfeature.js create mode 100644 srv/src/http/static/viz/1/goog/events/event.js create mode 100644 srv/src/http/static/viz/1/goog/events/eventid.js create mode 100644 srv/src/http/static/viz/1/goog/events/events.js create mode 100644 srv/src/http/static/viz/1/goog/events/eventtype.js create mode 100644 srv/src/http/static/viz/1/goog/events/listenable.js create mode 100644 srv/src/http/static/viz/1/goog/events/listener.js create mode 100644 srv/src/http/static/viz/1/goog/events/listenermap.js (limited to 'srv/src/http/static/viz/1/goog/events') diff --git a/srv/src/http/static/viz/1/goog/events/browserevent.js b/srv/src/http/static/viz/1/goog/events/browserevent.js new file mode 100644 index 0000000..14894e1 --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/browserevent.js @@ -0,0 +1,402 @@ +// 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. + * + *
+ * 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}.
+ * 
+ * + * @author arv@google.com (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} + */ +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; + + /** + * On touch devices use the first "changed touch" as the relevant touch. + * @type {Touch} + */ + var relevantTouch = e.changedTouches ? e.changedTouches[0] : null; + + // 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; + + if (!goog.isNull(relevantTouch)) { + this.clientX = relevantTouch.clientX !== undefined ? relevantTouch.clientX : + relevantTouch.pageX; + this.clientY = relevantTouch.clientY !== undefined ? relevantTouch.clientY : + relevantTouch.pageY; + this.screenX = relevantTouch.screenX || 0; + this.screenY = relevantTouch.screenY || 0; + } else { + // 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_; +}; diff --git a/srv/src/http/static/viz/1/goog/events/browserfeature.js b/srv/src/http/static/viz/1/goog/events/browserfeature.js new file mode 100644 index 0000000..4cfa8e3 --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/browserfeature.js @@ -0,0 +1,84 @@ +// 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'])) +}; diff --git a/srv/src/http/static/viz/1/goog/events/event.js b/srv/src/http/static/viz/1/goog/events/event.js new file mode 100644 index 0000000..89db91e --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/event.js @@ -0,0 +1,145 @@ +// 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. + * + * @suppress {underscore} Several properties on this class are technically + * public, but referencing these properties outside this package is strongly + * discouraged. + * + * @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 + */ + 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(); +}; diff --git a/srv/src/http/static/viz/1/goog/events/eventid.js b/srv/src/http/static/viz/1/goog/events/eventid.js new file mode 100644 index 0000000..9ff9e40 --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/eventid.js @@ -0,0 +1,46 @@ +// 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: + * + * /** @type {goog.events.EventId} *\ + * 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) {}); + * + * @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; +}; diff --git a/srv/src/http/static/viz/1/goog/events/events.js b/srv/src/http/static/viz/1/goog/events/events.js new file mode 100644 index 0000000..6a0acf7 --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/events.js @@ -0,0 +1,989 @@ +// 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: + *
+ * 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);
+ * 
+ * + * in IE and event object patching] + * @author arv@google.com (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" 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| + * !goog.events.EventId|!Array>} + * 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 if (src.attachEvent) { + // The else if above used to be an unconditional else. It would call + // exception on IE11, spoiling the day of some callers. The previous + // incarnation of this code, from 2007, indicates that it replaced an + // earlier still version that caused excess allocations on IE6. + src.attachEvent(goog.events.getOnString_(type.toString()), proxy); + } else { + throw Error('addEventListener and attachEvent are unavailable.'); + } + + 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 ...) 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| + * !goog.events.EventId|!Array>} + * 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| + * !goog.events.EventId|!Array>} + * 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 = key; + if (!listener || listener.removed) { + return false; + } + + var src = listener.src; + if (goog.events.Listenable.isImplementedBy(src)) { + return /** @type {!goog.events.Listenable} */ (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 /** @type {?} */ (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} Array of listener objects. + */ +goog.events.getListeners = function(obj, type, capture) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return /** @type {!goog.events.Listenable} */ (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} 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 /** @type {!goog.events.Listenable} */ (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 {unique} + */ +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 /** @type {?} */ (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_); + }); diff --git a/srv/src/http/static/viz/1/goog/events/eventtype.js b/srv/src/http/static/viz/1/goog/events/eventtype.js new file mode 100644 index 0000000..161e88a --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/eventtype.js @@ -0,0 +1,239 @@ +// 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 Event Types. + * + * @author arv@google.com (Erik Arvidsson) + */ + + +goog.provide('goog.events.EventType'); + +goog.require('goog.userAgent'); + + +/** + * Returns a prefixed event name for the current browser. + * @param {string} eventName The name of the event. + * @return {string} The prefixed event name. + * @suppress {missingRequire|missingProvide} + * @private + */ +goog.events.getVendorPrefixedName_ = function(eventName) { + return goog.userAgent.WEBKIT ? + 'webkit' + eventName : + (goog.userAgent.OPERA ? 'o' + eventName.toLowerCase() : + eventName.toLowerCase()); +}; + + +/** + * Constants for event names. + * @enum {string} + */ +goog.events.EventType = { + // Mouse events + CLICK: 'click', + RIGHTCLICK: 'rightclick', + DBLCLICK: 'dblclick', + MOUSEDOWN: 'mousedown', + MOUSEUP: 'mouseup', + MOUSEOVER: 'mouseover', + MOUSEOUT: 'mouseout', + MOUSEMOVE: 'mousemove', + MOUSEENTER: 'mouseenter', + MOUSELEAVE: 'mouseleave', + // Select start is non-standard. + // See http://msdn.microsoft.com/en-us/library/ie/ms536969(v=vs.85).aspx. + SELECTSTART: 'selectstart', // IE, Safari, Chrome + + // Wheel events + // http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents + WHEEL: 'wheel', + + // Key events + KEYPRESS: 'keypress', + KEYDOWN: 'keydown', + KEYUP: 'keyup', + + // Focus + BLUR: 'blur', + FOCUS: 'focus', + DEACTIVATE: 'deactivate', // IE only + // NOTE: The following two events are not stable in cross-browser usage. + // WebKit and Opera implement DOMFocusIn/Out. + // IE implements focusin/out. + // Gecko implements neither see bug at + // https://bugzilla.mozilla.org/show_bug.cgi?id=396927. + // The DOM Events Level 3 Draft deprecates DOMFocusIn in favor of focusin: + // http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html + // You can use FOCUS in Capture phase until implementations converge. + FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn', + FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut', + + // Forms + CHANGE: 'change', + RESET: 'reset', + SELECT: 'select', + SUBMIT: 'submit', + INPUT: 'input', + PROPERTYCHANGE: 'propertychange', // IE only + + // Drag and drop + DRAGSTART: 'dragstart', + DRAG: 'drag', + DRAGENTER: 'dragenter', + DRAGOVER: 'dragover', + DRAGLEAVE: 'dragleave', + DROP: 'drop', + DRAGEND: 'dragend', + + // Touch events + // Note that other touch events exist, but we should follow the W3C list here. + // http://www.w3.org/TR/touch-events/#list-of-touchevent-types + TOUCHSTART: 'touchstart', + TOUCHMOVE: 'touchmove', + TOUCHEND: 'touchend', + TOUCHCANCEL: 'touchcancel', + + // Misc + BEFOREUNLOAD: 'beforeunload', + CONSOLEMESSAGE: 'consolemessage', + CONTEXTMENU: 'contextmenu', + DOMCONTENTLOADED: 'DOMContentLoaded', + ERROR: 'error', + HELP: 'help', + LOAD: 'load', + LOSECAPTURE: 'losecapture', + ORIENTATIONCHANGE: 'orientationchange', + READYSTATECHANGE: 'readystatechange', + RESIZE: 'resize', + SCROLL: 'scroll', + TIMEUPDATE: 'timeupdate', + UNLOAD: 'unload', + + // HTML 5 History events + // See http://www.w3.org/TR/html5/browsers.html#event-definitions-0 + HASHCHANGE: 'hashchange', + PAGEHIDE: 'pagehide', + PAGESHOW: 'pageshow', + POPSTATE: 'popstate', + + // Copy and Paste + // Support is limited. Make sure it works on your favorite browser + // before using. + // http://www.quirksmode.org/dom/events/cutcopypaste.html + COPY: 'copy', + PASTE: 'paste', + CUT: 'cut', + BEFORECOPY: 'beforecopy', + BEFORECUT: 'beforecut', + BEFOREPASTE: 'beforepaste', + + // HTML5 online/offline events. + // http://www.w3.org/TR/offline-webapps/#related + ONLINE: 'online', + OFFLINE: 'offline', + + // HTML 5 worker events + MESSAGE: 'message', + CONNECT: 'connect', + + // CSS animation events. + /** @suppress {missingRequire} */ + ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'), + /** @suppress {missingRequire} */ + ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'), + /** @suppress {missingRequire} */ + ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'), + + // CSS transition events. Based on the browser support described at: + // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility + /** @suppress {missingRequire} */ + TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'), + + // W3C Pointer Events + // http://www.w3.org/TR/pointerevents/ + POINTERDOWN: 'pointerdown', + POINTERUP: 'pointerup', + POINTERCANCEL: 'pointercancel', + POINTERMOVE: 'pointermove', + POINTEROVER: 'pointerover', + POINTEROUT: 'pointerout', + POINTERENTER: 'pointerenter', + POINTERLEAVE: 'pointerleave', + GOTPOINTERCAPTURE: 'gotpointercapture', + LOSTPOINTERCAPTURE: 'lostpointercapture', + + // IE specific events. + // See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx + // Note: these events will be supplanted in IE11. + MSGESTURECHANGE: 'MSGestureChange', + MSGESTUREEND: 'MSGestureEnd', + MSGESTUREHOLD: 'MSGestureHold', + MSGESTURESTART: 'MSGestureStart', + MSGESTURETAP: 'MSGestureTap', + MSGOTPOINTERCAPTURE: 'MSGotPointerCapture', + MSINERTIASTART: 'MSInertiaStart', + MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture', + MSPOINTERCANCEL: 'MSPointerCancel', + MSPOINTERDOWN: 'MSPointerDown', + MSPOINTERENTER: 'MSPointerEnter', + MSPOINTERHOVER: 'MSPointerHover', + MSPOINTERLEAVE: 'MSPointerLeave', + MSPOINTERMOVE: 'MSPointerMove', + MSPOINTEROUT: 'MSPointerOut', + MSPOINTEROVER: 'MSPointerOver', + MSPOINTERUP: 'MSPointerUp', + + // Native IMEs/input tools events. + TEXT: 'text', + TEXTINPUT: 'textInput', + COMPOSITIONSTART: 'compositionstart', + COMPOSITIONUPDATE: 'compositionupdate', + COMPOSITIONEND: 'compositionend', + + // Webview tag events + // See http://developer.chrome.com/dev/apps/webview_tag.html + EXIT: 'exit', + LOADABORT: 'loadabort', + LOADCOMMIT: 'loadcommit', + LOADREDIRECT: 'loadredirect', + LOADSTART: 'loadstart', + LOADSTOP: 'loadstop', + RESPONSIVE: 'responsive', + SIZECHANGED: 'sizechanged', + UNRESPONSIVE: 'unresponsive', + + // HTML5 Page Visibility API. See details at + // {@code goog.labs.dom.PageVisibilityMonitor}. + VISIBILITYCHANGE: 'visibilitychange', + + // LocalStorage event. + STORAGE: 'storage', + + // DOM Level 2 mutation events (deprecated). + DOMSUBTREEMODIFIED: 'DOMSubtreeModified', + DOMNODEINSERTED: 'DOMNodeInserted', + DOMNODEREMOVED: 'DOMNodeRemoved', + DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument', + DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument', + DOMATTRMODIFIED: 'DOMAttrModified', + DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified', + + // Print events. + BEFOREPRINT: 'beforeprint', + AFTERPRINT: 'afterprint' +}; diff --git a/srv/src/http/static/viz/1/goog/events/listenable.js b/srv/src/http/static/viz/1/goog/events/listenable.js new file mode 100644 index 0000000..648d9fc --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/listenable.js @@ -0,0 +1,338 @@ +// Copyright 2012 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 interface for a listenable JavaScript object. + * @author chrishenry@google.com (Chris Henry) + */ + +goog.provide('goog.events.Listenable'); +goog.provide('goog.events.ListenableKey'); + +/** @suppress {extraRequire} */ +goog.require('goog.events.EventId'); + +goog.forwardDeclare('goog.events.EventLike'); +goog.forwardDeclare('goog.events.EventTarget'); + + + +/** + * A listenable interface. A listenable is an object with the ability + * to dispatch/broadcast events to "event listeners" registered via + * listen/listenOnce. + * + * The interface allows for an event propagation mechanism similar + * to one offered by native browser event targets, such as + * capture/bubble mechanism, stopping propagation, and preventing + * default actions. Capture/bubble mechanism depends on the ancestor + * tree constructed via {@code #getParentEventTarget}; this tree + * must be directed acyclic graph. The meaning of default action(s) + * in preventDefault is specific to a particular use case. + * + * Implementations that do not support capture/bubble or can not have + * a parent listenable can simply not implement any ability to set the + * parent listenable (and have {@code #getParentEventTarget} return + * null). + * + * Implementation of this class can be used with or independently from + * goog.events. + * + * Implementation must call {@code #addImplementation(implClass)}. + * + * @interface + * @see goog.events + * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html + */ +goog.events.Listenable = function() {}; + + +/** + * An expando property to indicate that an object implements + * goog.events.Listenable. + * + * See addImplementation/isImplementedBy. + * + * @type {string} + * @const + */ +goog.events.Listenable.IMPLEMENTED_BY_PROP = + 'closure_listenable_' + ((Math.random() * 1e6) | 0); + + +/** + * Marks a given class (constructor) as an implementation of + * Listenable, do that we can query that fact at runtime. The class + * must have already implemented the interface. + * @param {!Function} cls The class constructor. The corresponding + * class must have already implemented the interface. + */ +goog.events.Listenable.addImplementation = function(cls) { + cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true; +}; + + +/** + * @param {Object} obj The object to check. + * @return {boolean} Whether a given instance implements Listenable. The + * class/superclass of the instance must call addImplementation. + */ +goog.events.Listenable.isImplementedBy = function(obj) { + return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]); +}; + + +/** + * Adds an event listener. 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 {string|!goog.events.EventId} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {!goog.events.ListenableKey} Unique key for the listener. + * @template SCOPE,EVENTOBJ + */ +goog.events.Listenable.prototype.listen; + + +/** + * Adds an event listener that is removed automatically after the + * listener fired once. + * + * 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 {string|!goog.events.EventId} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {!goog.events.ListenableKey} Unique key for the listener. + * @template SCOPE,EVENTOBJ + */ +goog.events.Listenable.prototype.listenOnce; + + +/** + * Removes an event listener which was added with listen() or listenOnce(). + * + * @param {string|!goog.events.EventId} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call + * the listener. + * @return {boolean} Whether any listener was removed. + * @template SCOPE,EVENTOBJ + */ +goog.events.Listenable.prototype.unlisten; + + +/** + * Removes an event listener which was added with listen() by the key + * returned by listen(). + * + * @param {!goog.events.ListenableKey} key The key returned by + * listen() or listenOnce(). + * @return {boolean} Whether any listener was removed. + */ +goog.events.Listenable.prototype.unlistenByKey; + + +/** + * 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.EventLike} e Event object. + * @return {boolean} If anyone called preventDefault on the event object (or + * if any of the listeners returns false) this will also return false. + */ +goog.events.Listenable.prototype.dispatchEvent; + + +/** + * Removes all listeners from this listenable. If type is specified, + * it will only remove listeners of the particular type. otherwise all + * registered listeners will be removed. + * + * @param {string=} opt_type Type of event to remove, default is to + * remove all types. + * @return {number} Number of listeners removed. + */ +goog.events.Listenable.prototype.removeAllListeners; + + +/** + * Returns the parent of this event target to use for capture/bubble + * mechanism. + * + * NOTE(chrishenry): The name reflects the original implementation of + * custom event target ({@code goog.events.EventTarget}). We decided + * that changing the name is not worth it. + * + * @return {goog.events.Listenable} The parent EventTarget or null if + * there is no parent. + */ +goog.events.Listenable.prototype.getParentEventTarget; + + +/** + * Fires all registered listeners in this listenable for the given + * type and capture mode, passing them the given eventObject. This + * does not perform actual capture/bubble. Only implementors of the + * interface should be using this. + * + * @param {string|!goog.events.EventId} type The type of the + * listeners to fire. + * @param {boolean} capture The capture mode of the listeners to fire. + * @param {EVENTOBJ} eventObject The event object to fire. + * @return {boolean} Whether all listeners succeeded without + * attempting to prevent default behavior. If any listener returns + * false or called goog.events.Event#preventDefault, this returns + * false. + * @template EVENTOBJ + */ +goog.events.Listenable.prototype.fireListeners; + + +/** + * Gets all listeners in this listenable for the given type and + * capture mode. + * + * @param {string|!goog.events.EventId} type The type of the listeners to fire. + * @param {boolean} capture The capture mode of the listeners to fire. + * @return {!Array} An array of registered + * listeners. + * @template EVENTOBJ + */ +goog.events.Listenable.prototype.getListeners; + + +/** + * Gets the goog.events.ListenableKey for the event or null if no such + * listener is in use. + * + * @param {string|!goog.events.EventId} type The name of the event + * without the 'on' prefix. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The + * listener function to get. + * @param {boolean} capture Whether the listener is a capturing listener. + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} the found listener or null if not found. + * @template SCOPE,EVENTOBJ + */ +goog.events.Listenable.prototype.getListener; + + +/** + * Whether there is 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 {string|!goog.events.EventId=} opt_type Event type. + * @param {boolean=} opt_capture Whether to check for capture or bubble + * listeners. + * @return {boolean} Whether there is any active listeners matching + * the requested type and/or capture phase. + * @template EVENTOBJ + */ +goog.events.Listenable.prototype.hasListener; + + + +/** + * An interface that describes a single registered listener. + * @interface + */ +goog.events.ListenableKey = function() {}; + + +/** + * Counter used to create a unique key + * @type {number} + * @private + */ +goog.events.ListenableKey.counter_ = 0; + + +/** + * Reserves a key to be used for ListenableKey#key field. + * @return {number} A number to be used to fill ListenableKey#key + * field. + */ +goog.events.ListenableKey.reserveKey = function() { + return ++goog.events.ListenableKey.counter_; +}; + + +/** + * The source event target. + * @type {Object|goog.events.Listenable|goog.events.EventTarget} + */ +goog.events.ListenableKey.prototype.src; + + +/** + * The event type the listener is listening to. + * @type {string} + */ +goog.events.ListenableKey.prototype.type; + + +/** + * The listener function. + * @type {function(?):?|{handleEvent:function(?):?}|null} + */ +goog.events.ListenableKey.prototype.listener; + + +/** + * Whether the listener works on capture phase. + * @type {boolean} + */ +goog.events.ListenableKey.prototype.capture; + + +/** + * The 'this' object for the listener function's scope. + * @type {Object|undefined} + */ +goog.events.ListenableKey.prototype.handler; + + +/** + * A globally unique number to identify the key. + * @type {number} + */ +goog.events.ListenableKey.prototype.key; diff --git a/srv/src/http/static/viz/1/goog/events/listener.js b/srv/src/http/static/viz/1/goog/events/listener.js new file mode 100644 index 0000000..60c7370 --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/listener.js @@ -0,0 +1,131 @@ +// 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 Listener object. + * @see ../demos/events.html + */ + +goog.provide('goog.events.Listener'); + +goog.require('goog.events.ListenableKey'); + + + +/** + * Simple class that stores information about a listener + * @param {!Function} listener Callback function. + * @param {Function} proxy Wrapper for the listener that patches the event. + * @param {EventTarget|goog.events.Listenable} src Source object for + * the event. + * @param {string} type Event type. + * @param {boolean} capture Whether in capture or bubble phase. + * @param {Object=} opt_handler Object in whose context to execute the callback. + * @implements {goog.events.ListenableKey} + * @constructor + */ +goog.events.Listener = function( + listener, proxy, src, type, capture, opt_handler) { + if (goog.events.Listener.ENABLE_MONITORING) { + this.creationStack = new Error().stack; + } + + /** + * Callback function. + * @type {Function} + */ + this.listener = listener; + + /** + * A wrapper over the original listener. This is used solely to + * handle native browser events (it is used to simulate the capture + * phase and to patch the event object). + * @type {Function} + */ + this.proxy = proxy; + + /** + * Object or node that callback is listening to + * @type {EventTarget|goog.events.Listenable} + */ + this.src = src; + + /** + * The event type. + * @const {string} + */ + this.type = type; + + /** + * Whether the listener is being called in the capture or bubble phase + * @const {boolean} + */ + this.capture = !!capture; + + /** + * Optional object whose context to execute the listener in + * @type {Object|undefined} + */ + this.handler = opt_handler; + + /** + * The key of the listener. + * @const {number} + * @override + */ + this.key = goog.events.ListenableKey.reserveKey(); + + /** + * Whether to remove the listener after it has been called. + * @type {boolean} + */ + this.callOnce = false; + + /** + * Whether the listener has been removed. + * @type {boolean} + */ + this.removed = false; +}; + + +/** + * @define {boolean} Whether to enable the monitoring of the + * goog.events.Listener instances. Switching on the monitoring is only + * recommended for debugging because it has a significant impact on + * performance and memory usage. If switched off, the monitoring code + * compiles down to 0 bytes. + */ +goog.define('goog.events.Listener.ENABLE_MONITORING', false); + + +/** + * If monitoring the goog.events.Listener instances is enabled, stores the + * creation stack trace of the Disposable instance. + * @type {string} + */ +goog.events.Listener.prototype.creationStack; + + +/** + * Marks this listener as removed. This also remove references held by + * this listener object (such as listener and event source). + */ +goog.events.Listener.prototype.markAsRemoved = function() { + this.removed = true; + this.listener = null; + this.proxy = null; + this.src = null; + this.handler = null; +}; diff --git a/srv/src/http/static/viz/1/goog/events/listenermap.js b/srv/src/http/static/viz/1/goog/events/listenermap.js new file mode 100644 index 0000000..40cb848 --- /dev/null +++ b/srv/src/http/static/viz/1/goog/events/listenermap.js @@ -0,0 +1,306 @@ +// 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. + +/** + * @fileoverview A map of listeners that provides utility functions to + * deal with listeners on an event target. Used by + * {@code goog.events.EventTarget}. + * + * WARNING: Do not use this class from outside goog.events package. + * + * @visibility {//closure/goog/bin/sizetests:__pkg__} + * @visibility {//closure/goog/events:__pkg__} + * @visibility {//closure/goog/labs/events:__pkg__} + */ + +goog.provide('goog.events.ListenerMap'); + +goog.require('goog.array'); +goog.require('goog.events.Listener'); +goog.require('goog.object'); + + + +/** + * Creates a new listener map. + * @param {EventTarget|goog.events.Listenable} src The src object. + * @constructor + * @final + */ +goog.events.ListenerMap = function(src) { + /** @type {EventTarget|goog.events.Listenable} */ + this.src = src; + + /** + * Maps of event type to an array of listeners. + * @type {!Object>} + */ + this.listeners = {}; + + /** + * The count of types in this map that have registered listeners. + * @private {number} + */ + this.typeCount_ = 0; +}; + + +/** + * @return {number} The count of event types in this map that actually + * have registered listeners. + */ +goog.events.ListenerMap.prototype.getTypeCount = function() { + return this.typeCount_; +}; + + +/** + * @return {number} Total number of registered listeners. + */ +goog.events.ListenerMap.prototype.getListenerCount = function() { + var count = 0; + for (var type in this.listeners) { + count += this.listeners[type].length; + } + return count; +}; + + +/** + * Adds an event listener. 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 {string|!goog.events.EventId} type The listener event type. + * @param {!Function} listener This listener callback method. + * @param {boolean} callOnce Whether the listener is a one-off + * listener. + * @param {boolean=} opt_useCapture The capture mode of the listener. + * @param {Object=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {!goog.events.ListenableKey} Unique key for the listener. + */ +goog.events.ListenerMap.prototype.add = function( + type, listener, callOnce, opt_useCapture, opt_listenerScope) { + var typeStr = type.toString(); + var listenerArray = this.listeners[typeStr]; + if (!listenerArray) { + listenerArray = this.listeners[typeStr] = []; + this.typeCount_++; + } + + var listenerObj; + var index = goog.events.ListenerMap.findListenerIndex_( + listenerArray, listener, opt_useCapture, opt_listenerScope); + if (index > -1) { + listenerObj = listenerArray[index]; + if (!callOnce) { + // Ensure that, if there is an existing callOnce listener, it is no + // longer a callOnce listener. + listenerObj.callOnce = false; + } + } else { + listenerObj = new goog.events.Listener( + listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope); + listenerObj.callOnce = callOnce; + listenerArray.push(listenerObj); + } + return listenerObj; +}; + + +/** + * Removes a matching listener. + * @param {string|!goog.events.EventId} type The listener event type. + * @param {!Function} listener This listener callback method. + * @param {boolean=} opt_useCapture The capture mode of the listener. + * @param {Object=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {boolean} Whether any listener was removed. + */ +goog.events.ListenerMap.prototype.remove = function( + type, listener, opt_useCapture, opt_listenerScope) { + var typeStr = type.toString(); + if (!(typeStr in this.listeners)) { + return false; + } + + var listenerArray = this.listeners[typeStr]; + var index = goog.events.ListenerMap.findListenerIndex_( + listenerArray, listener, opt_useCapture, opt_listenerScope); + if (index > -1) { + var listenerObj = listenerArray[index]; + listenerObj.markAsRemoved(); + goog.array.removeAt(listenerArray, index); + if (listenerArray.length == 0) { + delete this.listeners[typeStr]; + this.typeCount_--; + } + return true; + } + return false; +}; + + +/** + * Removes the given listener object. + * @param {!goog.events.ListenableKey} listener The listener to remove. + * @return {boolean} Whether the listener is removed. + */ +goog.events.ListenerMap.prototype.removeByKey = function(listener) { + var type = listener.type; + if (!(type in this.listeners)) { + return false; + } + + var removed = goog.array.remove(this.listeners[type], listener); + if (removed) { + listener.markAsRemoved(); + if (this.listeners[type].length == 0) { + delete this.listeners[type]; + this.typeCount_--; + } + } + return removed; +}; + + +/** + * Removes all listeners from this map. If opt_type is provided, only + * listeners that match the given type are removed. + * @param {string|!goog.events.EventId=} opt_type Type of event to remove. + * @return {number} Number of listeners removed. + */ +goog.events.ListenerMap.prototype.removeAll = function(opt_type) { + var typeStr = opt_type && opt_type.toString(); + var count = 0; + for (var type in this.listeners) { + if (!typeStr || type == typeStr) { + var listenerArray = this.listeners[type]; + for (var i = 0; i < listenerArray.length; i++) { + ++count; + listenerArray[i].markAsRemoved(); + } + delete this.listeners[type]; + this.typeCount_--; + } + } + return count; +}; + + +/** + * Gets all listeners that match the given type and capture mode. The + * returned array is a copy (but the listener objects are not). + * @param {string|!goog.events.EventId} type The type of the listeners + * to retrieve. + * @param {boolean} capture The capture mode of the listeners to retrieve. + * @return {!Array} An array of matching + * listeners. + */ +goog.events.ListenerMap.prototype.getListeners = function(type, capture) { + var listenerArray = this.listeners[type.toString()]; + var rv = []; + if (listenerArray) { + for (var i = 0; i < listenerArray.length; ++i) { + var listenerObj = listenerArray[i]; + if (listenerObj.capture == capture) { + rv.push(listenerObj); + } + } + } + return rv; +}; + + +/** + * Gets the goog.events.ListenableKey for the event or null if no such + * listener is in use. + * + * @param {string|!goog.events.EventId} type The type of the listener + * to retrieve. + * @param {!Function} listener The listener function to get. + * @param {boolean} capture Whether the listener is a capturing listener. + * @param {Object=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} the found listener or null if not found. + */ +goog.events.ListenerMap.prototype.getListener = function( + type, listener, capture, opt_listenerScope) { + var listenerArray = this.listeners[type.toString()]; + var i = -1; + if (listenerArray) { + i = goog.events.ListenerMap.findListenerIndex_( + listenerArray, listener, capture, opt_listenerScope); + } + return i > -1 ? listenerArray[i] : null; +}; + + +/** + * Whether there is a matching listener. If either the type or capture + * parameters are unspecified, the function will match on the + * remaining criteria. + * + * @param {string|!goog.events.EventId=} opt_type The type of the listener. + * @param {boolean=} opt_capture The capture mode of the listener. + * @return {boolean} Whether there is an active listener matching + * the requested type and/or capture phase. + */ +goog.events.ListenerMap.prototype.hasListener = function( + opt_type, opt_capture) { + var hasType = goog.isDef(opt_type); + var typeStr = hasType ? opt_type.toString() : ''; + var hasCapture = goog.isDef(opt_capture); + + return goog.object.some(this.listeners, function(listenerArray, type) { + for (var i = 0; i < listenerArray.length; ++i) { + if ((!hasType || listenerArray[i].type == typeStr) && + (!hasCapture || listenerArray[i].capture == opt_capture)) { + return true; + } + } + + return false; + }); +}; + + +/** + * Finds the index of a matching goog.events.Listener in the given + * listenerArray. + * @param {!Array} listenerArray Array of listener. + * @param {!Function} listener The listener function. + * @param {boolean=} opt_useCapture The capture flag for the listener. + * @param {Object=} opt_listenerScope The listener scope. + * @return {number} The index of the matching listener within the + * listenerArray. + * @private + */ +goog.events.ListenerMap.findListenerIndex_ = function( + listenerArray, listener, opt_useCapture, opt_listenerScope) { + for (var i = 0; i < listenerArray.length; ++i) { + var listenerObj = listenerArray[i]; + if (!listenerObj.removed && listenerObj.listener == listener && + listenerObj.capture == !!opt_useCapture && + listenerObj.handler == opt_listenerScope) { + return i; + } + } + return -1; +}; -- cgit v1.2.3