summaryrefslogtreecommitdiff
path: root/src/http/static/viz/1/goog/events
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/static/viz/1/goog/events')
-rw-r--r--src/http/static/viz/1/goog/events/browserevent.js402
-rw-r--r--src/http/static/viz/1/goog/events/browserfeature.js84
-rw-r--r--src/http/static/viz/1/goog/events/event.js145
-rw-r--r--src/http/static/viz/1/goog/events/eventid.js46
-rw-r--r--src/http/static/viz/1/goog/events/events.js989
-rw-r--r--src/http/static/viz/1/goog/events/eventtype.js239
-rw-r--r--src/http/static/viz/1/goog/events/listenable.js338
-rw-r--r--src/http/static/viz/1/goog/events/listener.js131
-rw-r--r--src/http/static/viz/1/goog/events/listenermap.js306
9 files changed, 2680 insertions, 0 deletions
diff --git a/src/http/static/viz/1/goog/events/browserevent.js b/src/http/static/viz/1/goog/events/browserevent.js
new file mode 100644
index 0000000..14894e1
--- /dev/null
+++ b/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.
+ *
+ * <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 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<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;
+
+ /**
+ * 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/src/http/static/viz/1/goog/events/browserfeature.js b/src/http/static/viz/1/goog/events/browserfeature.js
new file mode 100644
index 0000000..4cfa8e3
--- /dev/null
+++ b/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/src/http/static/viz/1/goog/events/event.js b/src/http/static/viz/1/goog/events/event.js
new file mode 100644
index 0000000..89db91e
--- /dev/null
+++ b/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/src/http/static/viz/1/goog/events/eventid.js b/src/http/static/viz/1/goog/events/eventid.js
new file mode 100644
index 0000000..9ff9e40
--- /dev/null
+++ b/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<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) {});
+ *
+ * @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/src/http/static/viz/1/goog/events/events.js b/src/http/static/viz/1/goog/events/events.js
new file mode 100644
index 0000000..6a0acf7
--- /dev/null
+++ b/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:
+ * <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 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<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 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 <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 = 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<!goog.events.Listener>} 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<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 /** @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/src/http/static/viz/1/goog/events/eventtype.js b/src/http/static/viz/1/goog/events/eventtype.js
new file mode 100644
index 0000000..161e88a
--- /dev/null
+++ b/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/src/http/static/viz/1/goog/events/listenable.js b/src/http/static/viz/1/goog/events/listenable.js
new file mode 100644
index 0000000..648d9fc
--- /dev/null
+++ b/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<EVENTOBJ>} 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<EVENTOBJ>} 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<EVENTOBJ>} 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<EVENTOBJ>} 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<!goog.events.ListenableKey>} 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<EVENTOBJ>} 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<EVENTOBJ>=} 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/src/http/static/viz/1/goog/events/listener.js b/src/http/static/viz/1/goog/events/listener.js
new file mode 100644
index 0000000..60c7370
--- /dev/null
+++ b/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/src/http/static/viz/1/goog/events/listenermap.js b/src/http/static/viz/1/goog/events/listenermap.js
new file mode 100644
index 0000000..40cb848
--- /dev/null
+++ b/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<string, !Array<!goog.events.Listener>>}
+ */
+ 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<!goog.events.ListenableKey>} 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<!goog.events.Listener>} 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;
+};