flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ftho...@apache.org
Subject [17/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.
Date Thu, 17 Sep 2015 15:28:32 GMT
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/listenable.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/listenable.js b/externs/GCL/externs/goog/events/listenable.js
new file mode 100644
index 0000000..a05b348
--- /dev/null
+++ b/externs/GCL/externs/goog/events/listenable.js
@@ -0,0 +1,335 @@
+// 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');
+
+
+
+/**
+ * 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}
+ */
+goog.events.ListenableKey.prototype.handler;
+
+
+/**
+ * A globally unique number to identify the key.
+ * @type {number}
+ */
+goog.events.ListenableKey.prototype.key;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/listener.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/listener.js b/externs/GCL/externs/goog/events/listener.js
new file mode 100644
index 0000000..60c7370
--- /dev/null
+++ b/externs/GCL/externs/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;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/listenermap.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/listenermap.js b/externs/GCL/externs/goog/events/listenermap.js
new file mode 100644
index 0000000..c20cdb9
--- /dev/null
+++ b/externs/GCL/externs/goog/events/listenermap.js
@@ -0,0 +1,308 @@
+// 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;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/mousewheelhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/mousewheelhandler.js b/externs/GCL/externs/goog/events/mousewheelhandler.js
new file mode 100644
index 0000000..6729064
--- /dev/null
+++ b/externs/GCL/externs/goog/events/mousewheelhandler.js
@@ -0,0 +1,296 @@
+// Copyright 2006 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 This event wrapper will dispatch an event when the user uses
+ * the mouse wheel to scroll an element. You can get the direction by checking
+ * the deltaX and deltaY properties of the event.
+ *
+ * This class aims to smooth out inconsistencies between browser platforms with
+ * regards to mousewheel events, but we do not cover every possible
+ * software/hardware combination out there, some of which occasionally produce
+ * very large deltas in mousewheel events. If your application wants to guard
+ * against extremely large deltas, use the setMaxDeltaX and setMaxDeltaY APIs
+ * to set maximum values that make sense for your application.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/mousewheelhandler.html
+ */
+
+goog.provide('goog.events.MouseWheelEvent');
+goog.provide('goog.events.MouseWheelHandler');
+goog.provide('goog.events.MouseWheelHandler.EventType');
+
+goog.require('goog.dom');
+goog.require('goog.events');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventTarget');
+goog.require('goog.math');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * This event handler allows you to catch mouse wheel events in a consistent
+ * manner.
+ * @param {Element|Document} element The element to listen to the mouse wheel
+ *     event on.
+ * @param {boolean=} opt_capture Whether to handle the mouse wheel event in
+ *     capture phase.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.MouseWheelHandler = function(element, opt_capture) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * This is the element that we will listen to the real mouse wheel events on.
+   * @type {Element|Document}
+   * @private
+   */
+  this.element_ = element;
+
+  var rtlElement = goog.dom.isElement(this.element_) ?
+      /** @type {Element} */ (this.element_) :
+      (this.element_ ? /** @type {Document} */ (this.element_).body : null);
+
+  /**
+   * True if the element exists and is RTL, false otherwise.
+   * @type {boolean}
+   * @private
+   */
+  this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement);
+
+  var type = goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel';
+
+  /**
+   * The key returned from the goog.events.listen.
+   * @type {goog.events.Key}
+   * @private
+   */
+  this.listenKey_ = goog.events.listen(this.element_, type, this, opt_capture);
+};
+goog.inherits(goog.events.MouseWheelHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum type for the events fired by the mouse wheel handler.
+ * @enum {string}
+ */
+goog.events.MouseWheelHandler.EventType = {
+  MOUSEWHEEL: 'mousewheel'
+};
+
+
+/**
+ * Optional maximum magnitude for x delta on each mousewheel event.
+ * @type {number|undefined}
+ * @private
+ */
+goog.events.MouseWheelHandler.prototype.maxDeltaX_;
+
+
+/**
+ * Optional maximum magnitude for y delta on each mousewheel event.
+ * @type {number|undefined}
+ * @private
+ */
+goog.events.MouseWheelHandler.prototype.maxDeltaY_;
+
+
+/**
+ * @param {number} maxDeltaX Maximum magnitude for x delta on each mousewheel
+ *     event. Should be non-negative.
+ */
+goog.events.MouseWheelHandler.prototype.setMaxDeltaX = function(maxDeltaX) {
+  this.maxDeltaX_ = maxDeltaX;
+};
+
+
+/**
+ * @param {number} maxDeltaY Maximum magnitude for y delta on each mousewheel
+ *     event. Should be non-negative.
+ */
+goog.events.MouseWheelHandler.prototype.setMaxDeltaY = function(maxDeltaY) {
+  this.maxDeltaY_ = maxDeltaY;
+};
+
+
+/**
+ * Handles the events on the element.
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ */
+goog.events.MouseWheelHandler.prototype.handleEvent = function(e) {
+  var deltaX = 0;
+  var deltaY = 0;
+  var detail = 0;
+  var be = e.getBrowserEvent();
+  if (be.type == 'mousewheel') {
+    var wheelDeltaScaleFactor = 1;
+    if (goog.userAgent.IE ||
+        goog.userAgent.WEBKIT &&
+        (goog.userAgent.WINDOWS || goog.userAgent.isVersionOrHigher('532.0'))) {
+      // In IE we get a multiple of 120; we adjust to a multiple of 3 to
+      // represent number of lines scrolled (like Gecko).
+      // Newer versions of Webkit match IE behavior, and WebKit on
+      // Windows also matches IE behavior.
+      // See bug https://bugs.webkit.org/show_bug.cgi?id=24368
+      wheelDeltaScaleFactor = 40;
+    }
+
+    detail = goog.events.MouseWheelHandler.smartScale_(
+        -be.wheelDelta, wheelDeltaScaleFactor);
+    if (goog.isDef(be.wheelDeltaX)) {
+      // Webkit has two properties to indicate directional scroll, and
+      // can scroll both directions at once.
+      deltaX = goog.events.MouseWheelHandler.smartScale_(
+          -be.wheelDeltaX, wheelDeltaScaleFactor);
+      deltaY = goog.events.MouseWheelHandler.smartScale_(
+          -be.wheelDeltaY, wheelDeltaScaleFactor);
+    } else {
+      deltaY = detail;
+    }
+
+    // Historical note: Opera (pre 9.5) used to negate the detail value.
+  } else { // Gecko
+    // Gecko returns multiple of 3 (representing the number of lines scrolled)
+    detail = be.detail;
+
+    // Gecko sometimes returns really big values if the user changes settings to
+    // scroll a whole page per scroll
+    if (detail > 100) {
+      detail = 3;
+    } else if (detail < -100) {
+      detail = -3;
+    }
+
+    // Firefox 3.1 adds an axis field to the event to indicate direction of
+    // scroll.  See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
+    if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) {
+      deltaX = detail;
+    } else {
+      deltaY = detail;
+    }
+  }
+
+  if (goog.isNumber(this.maxDeltaX_)) {
+    deltaX = goog.math.clamp(deltaX, -this.maxDeltaX_, this.maxDeltaX_);
+  }
+  if (goog.isNumber(this.maxDeltaY_)) {
+    deltaY = goog.math.clamp(deltaY, -this.maxDeltaY_, this.maxDeltaY_);
+  }
+  // Don't clamp 'detail', since it could be ambiguous which axis it refers to
+  // and because it's informally deprecated anyways.
+
+  // For horizontal scrolling we need to flip the value for RTL grids.
+  if (this.isRtl_) {
+    deltaX = -deltaX;
+  }
+  var newEvent = new goog.events.MouseWheelEvent(detail, be, deltaX, deltaY);
+  this.dispatchEvent(newEvent);
+};
+
+
+/**
+ * Helper for scaling down a mousewheel delta by a scale factor, if appropriate.
+ * @param {number} mouseWheelDelta Delta from a mouse wheel event. Expected to
+ *     be an integer.
+ * @param {number} scaleFactor Factor to scale the delta down by. Expected to
+ *     be an integer.
+ * @return {number} Scaled-down delta value, or the original delta if the
+ *     scaleFactor does not appear to be applicable.
+ * @private
+ */
+goog.events.MouseWheelHandler.smartScale_ = function(mouseWheelDelta,
+    scaleFactor) {
+  // The basic problem here is that in Webkit on Mac and Linux, we can get two
+  // very different types of mousewheel events: from continuous devices
+  // (touchpads, Mighty Mouse) or non-continuous devices (normal wheel mice).
+  //
+  // Non-continuous devices in Webkit get their wheel deltas scaled up to
+  // behave like IE. Continuous devices return much smaller unscaled values
+  // (which most of the time will not be cleanly divisible by the IE scale
+  // factor), so we should not try to normalize them down.
+  //
+  // Detailed discussion:
+  //   https://bugs.webkit.org/show_bug.cgi?id=29601
+  //   http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
+  if (goog.userAgent.WEBKIT &&
+      (goog.userAgent.MAC || goog.userAgent.LINUX) &&
+      (mouseWheelDelta % scaleFactor) != 0) {
+    return mouseWheelDelta;
+  } else {
+    return mouseWheelDelta / scaleFactor;
+  }
+};
+
+
+/** @override */
+goog.events.MouseWheelHandler.prototype.disposeInternal = function() {
+  goog.events.MouseWheelHandler.superClass_.disposeInternal.call(this);
+  goog.events.unlistenByKey(this.listenKey_);
+  this.listenKey_ = null;
+};
+
+
+
+/**
+ * A base class for mouse wheel events. This is used with the
+ * MouseWheelHandler.
+ *
+ * @param {number} detail The number of rows the user scrolled.
+ * @param {Event} browserEvent Browser event object.
+ * @param {number} deltaX The number of rows the user scrolled in the X
+ *     direction.
+ * @param {number} deltaY The number of rows the user scrolled in the Y
+ *     direction.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.MouseWheelEvent = function(detail, browserEvent, deltaX, deltaY) {
+  goog.events.BrowserEvent.call(this, browserEvent);
+
+  this.type = goog.events.MouseWheelHandler.EventType.MOUSEWHEEL;
+
+  /**
+   * The number of lines the user scrolled
+   * @type {number}
+   * NOTE: Informally deprecated. Use deltaX and deltaY instead, they provide
+   * more information.
+   */
+  this.detail = detail;
+
+  /**
+   * The number of "lines" scrolled in the X direction.
+   *
+   * Note that not all browsers provide enough information to distinguish
+   * horizontal and vertical scroll events, so for these unsupported browsers,
+   * we will always have a deltaX of 0, even if the user scrolled their mouse
+   * wheel or trackpad sideways.
+   *
+   * Currently supported browsers are Webkit and Firefox 3.1 or later.
+   *
+   * @type {number}
+   */
+  this.deltaX = deltaX;
+
+  /**
+   * The number of lines scrolled in the Y direction.
+   * @type {number}
+   */
+  this.deltaY = deltaY;
+};
+goog.inherits(goog.events.MouseWheelEvent, goog.events.BrowserEvent);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/onlinehandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/onlinehandler.js b/externs/GCL/externs/goog/events/onlinehandler.js
new file mode 100644
index 0000000..5c9fb16
--- /dev/null
+++ b/externs/GCL/externs/goog/events/onlinehandler.js
@@ -0,0 +1,159 @@
+// Copyright 2008 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 This event handler will dispatch events when
+ * {@code navigator.onLine} changes.  HTML5 defines two events, online and
+ * offline that is fired on the window.  As of today 3 browsers support these
+ * events: Firefox 3 (Gecko 1.9), Opera 9.5, and IE8.  If we have any of these
+ * we listen to the 'online' and 'offline' events on the current window
+ * object.  Otherwise we poll the navigator.onLine property to detect changes.
+ *
+ * Note that this class only reflects what the browser tells us and this usually
+ * only reflects changes to the File -> Work Offline menu item.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/onlinehandler.html
+ */
+
+// TODO(arv): We should probably implement some kind of polling service and/or
+// a poll for changes event handler that can be used to fire events when a state
+// changes.
+
+goog.provide('goog.events.OnlineHandler');
+goog.provide('goog.events.OnlineHandler.EventType');
+
+goog.require('goog.Timer');
+goog.require('goog.events.BrowserFeature');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.net.NetworkStatusMonitor');
+
+
+
+/**
+ * Basic object for detecting whether the online state changes.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @implements {goog.net.NetworkStatusMonitor}
+ */
+goog.events.OnlineHandler = function() {
+  goog.events.OnlineHandler.base(this, 'constructor');
+
+  /**
+   * @private {goog.events.EventHandler<!goog.events.OnlineHandler>}
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  // Some browsers do not support navigator.onLine and therefore we don't
+  // bother setting up events or timers.
+  if (!goog.events.BrowserFeature.HAS_NAVIGATOR_ONLINE_PROPERTY) {
+    return;
+  }
+
+  if (goog.events.BrowserFeature.HAS_HTML5_NETWORK_EVENT_SUPPORT) {
+    var target =
+        goog.events.BrowserFeature.HTML5_NETWORK_EVENTS_FIRE_ON_BODY ?
+        document.body : window;
+    this.eventHandler_.listen(target,
+        [goog.events.EventType.ONLINE, goog.events.EventType.OFFLINE],
+        this.handleChange_);
+  } else {
+    this.online_ = this.isOnline();
+    this.timer_ = new goog.Timer(goog.events.OnlineHandler.POLL_INTERVAL_);
+    this.eventHandler_.listen(this.timer_, goog.Timer.TICK, this.handleTick_);
+    this.timer_.start();
+  }
+};
+goog.inherits(goog.events.OnlineHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum for the events dispatched by the OnlineHandler.
+ * @enum {string}
+ * @deprecated Use goog.net.NetworkStatusMonitor.EventType instead.
+ */
+goog.events.OnlineHandler.EventType = goog.net.NetworkStatusMonitor.EventType;
+
+
+/**
+ * The time to wait before checking the {@code navigator.onLine} again.
+ * @type {number}
+ * @private
+ */
+goog.events.OnlineHandler.POLL_INTERVAL_ = 250;
+
+
+/**
+ * Stores the last value of the online state so we can detect if this has
+ * changed.
+ * @type {boolean}
+ * @private
+ */
+goog.events.OnlineHandler.prototype.online_;
+
+
+/**
+ * The timer object used to poll the online state.
+ * @type {goog.Timer}
+ * @private
+ */
+goog.events.OnlineHandler.prototype.timer_;
+
+
+/** @override */
+goog.events.OnlineHandler.prototype.isOnline = function() {
+  return goog.events.BrowserFeature.HAS_NAVIGATOR_ONLINE_PROPERTY ?
+      navigator.onLine : true;
+};
+
+
+/**
+ * Called every time the timer ticks to see if the state has changed and when
+ * the online state changes the method handleChange_ is called.
+ * @private
+ */
+goog.events.OnlineHandler.prototype.handleTick_ = function() {
+  var online = this.isOnline();
+  if (online != this.online_) {
+    this.online_ = online;
+    this.handleChange_();
+  }
+};
+
+
+/**
+ * Called when the online state changes.  This dispatches the
+ * {@code ONLINE} and {@code OFFLINE} events respectively.
+ * @private
+ */
+goog.events.OnlineHandler.prototype.handleChange_ = function() {
+  var type = this.isOnline() ?
+      goog.net.NetworkStatusMonitor.EventType.ONLINE :
+      goog.net.NetworkStatusMonitor.EventType.OFFLINE;
+  this.dispatchEvent(type);
+};
+
+
+/** @override */
+goog.events.OnlineHandler.prototype.disposeInternal = function() {
+  goog.events.OnlineHandler.base(this, 'disposeInternal');
+  this.eventHandler_.dispose();
+  this.eventHandler_ = null;
+  if (this.timer_) {
+    this.timer_.dispose();
+    this.timer_ = null;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/pastehandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/pastehandler.js b/externs/GCL/externs/goog/events/pastehandler.js
new file mode 100644
index 0000000..4992ff0
--- /dev/null
+++ b/externs/GCL/externs/goog/events/pastehandler.js
@@ -0,0 +1,517 @@
+// Copyright 2009 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 Provides a 'paste' event detector that works consistently
+ * across different browsers.
+ *
+ * IE5, IE6, IE7, Safari3.0 and FF3.0 all fire 'paste' events on textareas.
+ * FF2 doesn't. This class uses 'paste' events when they are available
+ * and uses heuristics to detect the 'paste' event when they are not available.
+ *
+ * Known issue: will not detect paste events in FF2 if you pasted exactly the
+ * same existing text.
+ * Known issue: Opera + Mac doesn't work properly because of the meta key. We
+ * can probably fix that. TODO(user): {@link KeyboardShortcutHandler} does not
+ * work either very well with opera + mac. fix that.
+ *
+ * @supported IE5, IE6, IE7, Safari3.0, Chrome, FF2.0 (linux) and FF3.0 and
+ * Opera (mac and windows).
+ *
+ * @see ../demos/pastehandler.html
+ */
+
+goog.provide('goog.events.PasteHandler');
+goog.provide('goog.events.PasteHandler.EventType');
+goog.provide('goog.events.PasteHandler.State');
+
+goog.require('goog.Timer');
+goog.require('goog.async.ConditionalDelay');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.log');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A paste event detector. Gets an {@code element} as parameter and fires
+ * {@code goog.events.PasteHandler.EventType.PASTE} events when text is
+ * pasted in the {@code element}. Uses heuristics to detect paste events in FF2.
+ * See more details of the heuristic on {@link #handleEvent_}.
+ *
+ * @param {Element} element The textarea element we are listening on.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.PasteHandler = function(element) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * The element that you want to listen for paste events on.
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  /**
+   * The last known value of the element. Kept to check if things changed. See
+   * more details on {@link #handleEvent_}.
+   * @type {string}
+   * @private
+   */
+  this.oldValue_ = this.element_.value;
+
+  /**
+   * Handler for events.
+   * @type {goog.events.EventHandler<!goog.events.PasteHandler>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  /**
+   * The last time an event occurred on the element. Kept to check whether the
+   * last event was generated by two input events or by multiple fast key events
+   * that got swallowed. See more details on {@link #handleEvent_}.
+   * @type {number}
+   * @private
+   */
+  this.lastTime_ = goog.now();
+
+  if (goog.userAgent.WEBKIT ||
+      goog.userAgent.IE ||
+      goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9')) {
+    // Most modern browsers support the paste event.
+    this.eventHandler_.listen(element, goog.events.EventType.PASTE,
+        this.dispatch_);
+  } else {
+    // But FF2 and Opera doesn't. we listen for a series of events to try to
+    // find out if a paste occurred. We enumerate and cover all known ways to
+    // paste text on textareas.  See more details on {@link #handleEvent_}.
+    var events = [
+      goog.events.EventType.KEYDOWN,
+      goog.events.EventType.BLUR,
+      goog.events.EventType.FOCUS,
+      goog.events.EventType.MOUSEOVER,
+      'input'
+    ];
+    this.eventHandler_.listen(element, events, this.handleEvent_);
+  }
+
+  /**
+   * ConditionalDelay used to poll for changes in the text element once users
+   * paste text. Browsers fire paste events BEFORE the text is actually present
+   * in the element.value property.
+   * @type {goog.async.ConditionalDelay}
+   * @private
+   */
+  this.delay_ = new goog.async.ConditionalDelay(
+      goog.bind(this.checkUpdatedText_, this));
+
+};
+goog.inherits(goog.events.PasteHandler, goog.events.EventTarget);
+
+
+/**
+ * The types of events fired by this class.
+ * @enum {string}
+ */
+goog.events.PasteHandler.EventType = {
+  /**
+   * Dispatched as soon as the paste event is detected, but before the pasted
+   * text has been added to the text element we're listening to.
+   */
+  PASTE: 'paste',
+
+  /**
+   * Dispatched after detecting a change to the value of text element
+   * (within 200msec of receiving the PASTE event).
+   */
+  AFTER_PASTE: 'after_paste'
+};
+
+
+/**
+ * The mandatory delay we expect between two {@code input} events, used to
+ * differentiated between non key paste events and key events.
+ * @type {number}
+ */
+goog.events.PasteHandler.MANDATORY_MS_BETWEEN_INPUT_EVENTS_TIE_BREAKER =
+    400;
+
+
+/**
+ * The period between each time we check whether the pasted text appears in the
+ * text element or not.
+ * @type {number}
+ * @private
+ */
+goog.events.PasteHandler.PASTE_POLLING_PERIOD_MS_ = 50;
+
+
+/**
+ * The maximum amount of time we want to poll for changes.
+ * @type {number}
+ * @private
+ */
+goog.events.PasteHandler.PASTE_POLLING_TIMEOUT_MS_ = 200;
+
+
+/**
+ * The states that this class can be found, on the paste detection algorithm.
+ * @enum {string}
+ */
+goog.events.PasteHandler.State = {
+  INIT: 'init',
+  FOCUSED: 'focused',
+  TYPING: 'typing'
+};
+
+
+/**
+ * The initial state of the paste detection algorithm.
+ * @type {goog.events.PasteHandler.State}
+ * @private
+ */
+goog.events.PasteHandler.prototype.state_ =
+    goog.events.PasteHandler.State.INIT;
+
+
+/**
+ * The previous event that caused us to be on the current state.
+ * @type {?string}
+ * @private
+ */
+goog.events.PasteHandler.prototype.previousEvent_;
+
+
+/**
+ * A logger, used to help us debug the algorithm.
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.events.PasteHandler.prototype.logger_ =
+    goog.log.getLogger('goog.events.PasteHandler');
+
+
+/** @override */
+goog.events.PasteHandler.prototype.disposeInternal = function() {
+  goog.events.PasteHandler.superClass_.disposeInternal.call(this);
+  this.eventHandler_.dispose();
+  this.eventHandler_ = null;
+  this.delay_.dispose();
+  this.delay_ = null;
+};
+
+
+/**
+ * Returns the current state of the paste detection algorithm. Used mostly for
+ * testing.
+ * @return {goog.events.PasteHandler.State} The current state of the class.
+ */
+goog.events.PasteHandler.prototype.getState = function() {
+  return this.state_;
+};
+
+
+/**
+ * Returns the event handler.
+ * @return {goog.events.EventHandler<T>} The event handler.
+ * @protected
+ * @this T
+ * @template T
+ */
+goog.events.PasteHandler.prototype.getEventHandler = function() {
+  return this.eventHandler_;
+};
+
+
+/**
+ * Checks whether the element.value property was updated, and if so, dispatches
+ * the event that let clients know that the text is available.
+ * @return {boolean} Whether the polling should stop or not, based on whether
+ *     we found a text change or not.
+ * @private
+ */
+goog.events.PasteHandler.prototype.checkUpdatedText_ = function() {
+  if (this.oldValue_ == this.element_.value) {
+    return false;
+  }
+  goog.log.info(this.logger_, 'detected textchange after paste');
+  this.dispatchEvent(goog.events.PasteHandler.EventType.AFTER_PASTE);
+  return true;
+};
+
+
+/**
+ * Dispatches the paste event.
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.dispatch_ = function(e) {
+  var event = new goog.events.BrowserEvent(e.getBrowserEvent());
+  event.type = goog.events.PasteHandler.EventType.PASTE;
+  this.dispatchEvent(event);
+
+  // Starts polling for updates in the element.value property so we can tell
+  // when do dispatch the AFTER_PASTE event. (We do an initial check after an
+  // async delay of 0 msec since some browsers update the text right away and
+  // our poller will always wait one period before checking).
+  goog.Timer.callOnce(function() {
+    if (!this.checkUpdatedText_()) {
+      this.delay_.start(
+          goog.events.PasteHandler.PASTE_POLLING_PERIOD_MS_,
+          goog.events.PasteHandler.PASTE_POLLING_TIMEOUT_MS_);
+    }
+  }, 0, this);
+};
+
+
+/**
+ * The main event handler which implements a state machine.
+ *
+ * To handle FF2, we enumerate and cover all the known ways a user can paste:
+ *
+ * 1) ctrl+v, shift+insert, cmd+v
+ * 2) right click -> paste
+ * 3) edit menu -> paste
+ * 4) drag and drop
+ * 5) middle click
+ *
+ * (1) is easy and can be detected by listening for key events and finding out
+ * which keys are pressed. (2), (3), (4) and (5) do not generate a key event,
+ * so we need to listen for more than that. (2-5) all generate 'input' events,
+ * but so does key events. So we need to have some sort of 'how did the input
+ * event was generated' history algorithm.
+ *
+ * (2) is an interesting case in Opera on a Mac: since Macs does not have two
+ * buttons, right clicking involves pressing the CTRL key. Even more interesting
+ * is the fact that opera does NOT set the e.ctrlKey bit. Instead, it sets
+ * e.keyCode = 0.
+ * {@link http://www.quirksmode.org/js/keys.html}
+ *
+ * (1) is also an interesting case in Opera on a Mac: Opera is the only browser
+ * covered by this class that can detect the cmd key (FF2 can't apparently). And
+ * it fires e.keyCode = 17, which is the CTRL key code.
+ * {@link http://www.quirksmode.org/js/keys.html}
+ *
+ * NOTE(user, pbarry): There is an interesting thing about (5): on Linux, (5)
+ * pastes the last thing that you highlighted, not the last thing that you
+ * ctrl+c'ed. This code will still generate a {@code PASTE} event though.
+ *
+ * We enumerate all the possible steps a user can take to paste text and we
+ * implemented the transition between the steps in a state machine. The
+ * following is the design of the state machine:
+ *
+ * matching paths:
+ *
+ * (1) happens on INIT -> FOCUSED -> TYPING -> [e.ctrlKey & e.keyCode = 'v']
+ * (2-3) happens on INIT -> FOCUSED -> [input event happened]
+ * (4) happens on INIT -> [mouseover && text changed]
+ *
+ * non matching paths:
+ *
+ * user is typing normally
+ * INIT -> FOCUS -> TYPING -> INPUT -> INIT
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleEvent_ = function(e) {
+  // transition between states happen at each browser event, and depend on the
+  // current state, the event that led to this state, and the event input.
+  switch (this.state_) {
+    case goog.events.PasteHandler.State.INIT: {
+      this.handleUnderInit_(e);
+      break;
+    }
+    case goog.events.PasteHandler.State.FOCUSED: {
+      this.handleUnderFocused_(e);
+      break;
+    }
+    case goog.events.PasteHandler.State.TYPING: {
+      this.handleUnderTyping_(e);
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_, 'invalid ' + this.state_ + ' state');
+    }
+  }
+  this.lastTime_ = goog.now();
+  this.oldValue_ = this.element_.value;
+  goog.log.info(this.logger_, e.type + ' -> ' + this.state_);
+  this.previousEvent_ = e.type;
+};
+
+
+/**
+ * {@code goog.events.PasteHandler.EventType.INIT} is the first initial state
+ * the textarea is found. You can only leave this state by setting focus on the
+ * textarea, which is how users will input text. You can also paste things using
+ * drag and drop, which will not generate a {@code goog.events.EventType.FOCUS}
+ * event, but will generate a {@code goog.events.EventType.MOUSEOVER}.
+ *
+ * For browsers that support the 'paste' event, we match it and stay on the same
+ * state.
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleUnderInit_ = function(e) {
+  switch (e.type) {
+    case goog.events.EventType.BLUR: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      break;
+    }
+    case goog.events.EventType.FOCUS: {
+      this.state_ = goog.events.PasteHandler.State.FOCUSED;
+      break;
+    }
+    case goog.events.EventType.MOUSEOVER: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      if (this.element_.value != this.oldValue_) {
+        goog.log.info(this.logger_, 'paste by dragdrop while on init!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_,
+          'unexpected event ' + e.type + 'during init');
+    }
+  }
+};
+
+
+/**
+ * {@code goog.events.PasteHandler.EventType.FOCUSED} is typically the second
+ * state the textarea will be, which is followed by the {@code INIT} state. On
+ * this state, users can paste in three different ways: edit -> paste,
+ * right click -> paste and drag and drop.
+ *
+ * The latter will generate a {@code goog.events.EventType.MOUSEOVER} event,
+ * which we match by making sure the textarea text changed. The first two will
+ * generate an 'input', which we match by making sure it was NOT generated by a
+ * key event (which also generates an 'input' event).
+ *
+ * Unfortunately, in Firefox, if you type fast, some KEYDOWN events are
+ * swallowed but an INPUT event may still happen. That means we need to
+ * differentiate between two consecutive INPUT events being generated either by
+ * swallowed key events OR by a valid edit -> paste -> edit -> paste action. We
+ * do this by checking a minimum time between the two events. This heuristic
+ * seems to work well, but it is obviously a heuristic :).
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleUnderFocused_ = function(e) {
+  switch (e.type) {
+    case 'input' : {
+      // there are two different events that happen in practice that involves
+      // consecutive 'input' events. we use a heuristic to differentiate
+      // between the one that generates a valid paste action and the one that
+      // doesn't.
+      // @see testTypingReallyFastDispatchesTwoInputEventsBeforeTheKEYDOWNEvent
+      // and
+      // @see testRightClickRightClickAlsoDispatchesTwoConsecutiveInputEvents
+      // Notice that an 'input' event may be also triggered by a 'middle click'
+      // paste event, which is described in
+      // @see testMiddleClickWithoutFocusTriggersPasteEvent
+      var minimumMilisecondsBetweenInputEvents = this.lastTime_ +
+          goog.events.PasteHandler.
+              MANDATORY_MS_BETWEEN_INPUT_EVENTS_TIE_BREAKER;
+      if (goog.now() > minimumMilisecondsBetweenInputEvents ||
+          this.previousEvent_ == goog.events.EventType.FOCUS) {
+        goog.log.info(this.logger_, 'paste by textchange while focused!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    case goog.events.EventType.BLUR: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      break;
+    }
+    case goog.events.EventType.KEYDOWN: {
+      goog.log.info(this.logger_, 'key down ... looking for ctrl+v');
+      // Opera + MAC does not set e.ctrlKey. Instead, it gives me e.keyCode = 0.
+      // http://www.quirksmode.org/js/keys.html
+      if (goog.userAgent.MAC && goog.userAgent.OPERA && e.keyCode == 0 ||
+          goog.userAgent.MAC && goog.userAgent.OPERA && e.keyCode == 17) {
+        break;
+      }
+      this.state_ = goog.events.PasteHandler.State.TYPING;
+      break;
+    }
+    case goog.events.EventType.MOUSEOVER: {
+      if (this.element_.value != this.oldValue_) {
+        goog.log.info(this.logger_, 'paste by dragdrop while focused!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_,
+          'unexpected event ' + e.type + ' during focused');
+    }
+  }
+};
+
+
+/**
+ * {@code goog.events.PasteHandler.EventType.TYPING} is the third state
+ * this class can be. It exists because each KEYPRESS event will ALSO generate
+ * an INPUT event (because the textarea value changes), and we need to
+ * differentiate between an INPUT event generated by a key event and an INPUT
+ * event generated by edit -> paste actions.
+ *
+ * This is the state that we match the ctrl+v pattern.
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleUnderTyping_ = function(e) {
+  switch (e.type) {
+    case 'input' : {
+      this.state_ = goog.events.PasteHandler.State.FOCUSED;
+      break;
+    }
+    case goog.events.EventType.BLUR: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      break;
+    }
+    case goog.events.EventType.KEYDOWN: {
+      if (e.ctrlKey && e.keyCode == goog.events.KeyCodes.V ||
+          e.shiftKey && e.keyCode == goog.events.KeyCodes.INSERT ||
+          e.metaKey && e.keyCode == goog.events.KeyCodes.V) {
+        goog.log.info(this.logger_, 'paste by ctrl+v while keypressed!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    case goog.events.EventType.MOUSEOVER: {
+      if (this.element_.value != this.oldValue_) {
+        goog.log.info(this.logger_, 'paste by dragdrop while keypressed!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_,
+          'unexpected event ' + e.type + ' during keypressed');
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/wheelevent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/wheelevent.js b/externs/GCL/externs/goog/events/wheelevent.js
new file mode 100644
index 0000000..1f172eb
--- /dev/null
+++ b/externs/GCL/externs/goog/events/wheelevent.js
@@ -0,0 +1,169 @@
+// Copyright 2014 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 This class aims to smooth out inconsistencies between browser
+ * handling of wheel events by providing an event that is similar to that
+ * defined in the standard, but also easier to consume.
+ *
+ * It is based upon the WheelEvent, which allows for up to 3 dimensional
+ * scrolling events that come in units of either pixels, lines or pages.
+ * http://www.w3.org/TR/2014/WD-DOM-Level-3-Events-20140925/#interface-WheelEvent
+ *
+ * The significant difference here is that it also provides reasonable pixel
+ * deltas for clients that do not want to treat line and page scrolling events
+ * specially.
+ *
+ * Clients of this code should be aware that some input devices only fire a few
+ * discrete events (such as a mouse wheel without acceleration) whereas some can
+ * generate a large number of events for a single interaction (such as a
+ * touchpad with acceleration). There is no signal in the events to reliably
+ * distinguish between these.
+ *
+ * @see ../demos/wheelhandler.html
+ */
+
+goog.provide('goog.events.WheelEvent');
+
+goog.require('goog.asserts');
+goog.require('goog.events.BrowserEvent');
+
+
+
+/**
+ * A common class for wheel events. This is used with the WheelHandler.
+ *
+ * @param {Event} browserEvent Browser event object.
+ * @param {goog.events.WheelEvent.DeltaMode} deltaMode The delta mode units of
+ *     the wheel event.
+ * @param {number} deltaX The number of delta units the user in the X axis.
+ * @param {number} deltaY The number of delta units the user in the Y axis.
+ * @param {number} deltaZ The number of delta units the user in the Z axis.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.WheelEvent = function(
+    browserEvent, deltaMode, deltaX, deltaY, deltaZ) {
+  goog.events.WheelEvent.base(this, 'constructor', browserEvent);
+  goog.asserts.assert(browserEvent, 'Expecting a non-null browserEvent');
+
+  /** @type {goog.events.WheelEvent.EventType} */
+  this.type = goog.events.WheelEvent.EventType.WHEEL;
+
+  /**
+   * An enum corresponding to the units of this event.
+   * @type {goog.events.WheelEvent.DeltaMode}
+   */
+  this.deltaMode = deltaMode;
+
+  /**
+   * The number of delta units in the X axis.
+   * @type {number}
+   */
+  this.deltaX = deltaX;
+
+  /**
+   * The number of delta units in the Y axis.
+   * @type {number}
+   */
+  this.deltaY = deltaY;
+
+  /**
+   * The number of delta units in the Z axis.
+   * @type {number}
+   */
+  this.deltaZ = deltaZ;
+
+  // Ratio between delta and pixel values.
+  var pixelRatio = 1;  // Value for DeltaMode.PIXEL
+  switch (deltaMode) {
+    case goog.events.WheelEvent.DeltaMode.PAGE:
+      pixelRatio *= goog.events.WheelEvent.PIXELS_PER_PAGE_;
+      break;
+    case goog.events.WheelEvent.DeltaMode.LINE:
+      pixelRatio *= goog.events.WheelEvent.PIXELS_PER_LINE_;
+      break;
+  }
+
+  /**
+   * The number of delta pixels in the X axis. Code that doesn't want to handle
+   * different deltaMode units can just look here.
+   * @type {number}
+   */
+  this.pixelDeltaX = this.deltaX * pixelRatio;
+
+  /**
+   * The number of pixels in the Y axis. Code that doesn't want to
+   * handle different deltaMode units can just look here.
+   * @type {number}
+   */
+  this.pixelDeltaY = this.deltaY * pixelRatio;
+
+  /**
+   * The number of pixels scrolled in the Z axis. Code that doesn't want to
+   * handle different deltaMode units can just look here.
+   * @type {number}
+   */
+  this.pixelDeltaZ = this.deltaZ * pixelRatio;
+};
+goog.inherits(goog.events.WheelEvent, goog.events.BrowserEvent);
+
+
+/**
+ * Enum type for the events fired by the wheel handler.
+ * @enum {string}
+ */
+goog.events.WheelEvent.EventType = {
+  /** The user has provided wheel-based input. */
+  WHEEL: 'wheel'
+};
+
+
+/**
+ * Units for the deltas in a WheelEvent.
+ * @enum {number}
+ */
+goog.events.WheelEvent.DeltaMode = {
+  /** The units are in pixels. From DOM_DELTA_PIXEL. */
+  PIXEL: 0,
+  /** The units are in lines. From DOM_DELTA_LINE. */
+  LINE: 1,
+  /** The units are in pages. From DOM_DELTA_PAGE. */
+  PAGE: 2
+};
+
+
+/**
+ * A conversion number between line scroll units and pixel scroll units. The
+ * actual value per line can vary a lot between devices and font sizes. This
+ * number can not be perfect, but it should be reasonable for converting lines
+ * scroll events into pixels.
+ * @const {number}
+ * @private
+ */
+goog.events.WheelEvent.PIXELS_PER_LINE_ = 15;
+
+
+/**
+ * A conversion number between page scroll units and pixel scroll units. The
+ * actual value per page can vary a lot as many different devices have different
+ * screen sizes, and the window might not be taking up the full screen. This
+ * number can not be perfect, but it should be reasonable for converting page
+ * scroll events into pixels.
+ * @const {number}
+ * @private
+ */
+goog.events.WheelEvent.PIXELS_PER_PAGE_ = 30 *
+    goog.events.WheelEvent.PIXELS_PER_LINE_;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/wheelhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/wheelhandler.js b/externs/GCL/externs/goog/events/wheelhandler.js
new file mode 100644
index 0000000..9d0f1e3
--- /dev/null
+++ b/externs/GCL/externs/goog/events/wheelhandler.js
@@ -0,0 +1,159 @@
+// Copyright 2014 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 This event wrapper will dispatch an event when the user uses
+ * the wheel on an element. The event provides details of the unit type (pixel /
+ * line / page) and deltas in those units in up to 3 dimensions. Additionally,
+ * simplified pixel deltas are provided for code that doesn't need to handle the
+ * different units differently. This is not to be confused with the scroll
+ * event, where an element in the dom can report that it was scrolled.
+ *
+ * This class aims to smooth out inconsistencies between browser platforms with
+ * regards to wheel events, but we do not cover every possible software/hardware
+ * combination out there, some of which occasionally produce very large deltas
+ * in wheel events, especially when the device supports acceleration.
+ *
+ * Relevant standard:
+ * http://www.w3.org/TR/2014/WD-DOM-Level-3-Events-20140925/#interface-WheelEvent
+ *
+ * Clients of this code should be aware that some input devices only fire a few
+ * discrete events (such as a mouse wheel without acceleration) whereas some can
+ * generate a large number of events for a single interaction (such as a
+ * touchpad with acceleration). There is no signal in the events to reliably
+ * distinguish between these.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/wheelhandler.html
+ */
+
+goog.provide('goog.events.WheelHandler');
+
+goog.require('goog.dom');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.WheelEvent');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+goog.require('goog.userAgent.product');
+goog.require('goog.userAgent.product.isVersion');
+
+
+
+/**
+ * This event handler allows you to catch wheel events in a consistent manner.
+ * @param {!Element|!Document} element The element to listen to the wheel event
+ *     on.
+ * @param {boolean=} opt_capture Whether to handle the wheel event in capture
+ *     phase.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.WheelHandler = function(element, opt_capture) {
+  goog.events.WheelHandler.base(this, 'constructor');
+
+  /**
+   * This is the element that we will listen to the real wheel events on.
+   * @private {!Element|!Document}
+   */
+  this.element_ = element;
+
+  var rtlElement = goog.dom.isElement(this.element_) ?
+      /** @type {!Element} */ (this.element_) :
+      /** @type {!Document} */ (this.element_).body;
+
+  /**
+   * True if the element exists and is RTL, false otherwise.
+   * @private {boolean}
+   */
+  this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement);
+
+  /**
+   * The key returned from the goog.events.listen.
+   * @private {goog.events.Key}
+   */
+  this.listenKey_ = goog.events.listen(
+      this.element_, goog.events.WheelHandler.getDomEventType(),
+      this, opt_capture);
+};
+goog.inherits(goog.events.WheelHandler, goog.events.EventTarget);
+
+
+/**
+ * Returns the dom event type.
+ * @return {string} The dom event type.
+ */
+goog.events.WheelHandler.getDomEventType = function() {
+  // Prefer to use wheel events whenever supported.
+  if (goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher(17) ||
+      goog.userAgent.IE && goog.userAgent.isVersionOrHigher(9) ||
+      goog.userAgent.product.CHROME && goog.userAgent.product.isVersion(31)) {
+    return 'wheel';
+  }
+
+  // Legacy events. Still the best we have on Opera and Safari.
+  return goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel';
+};
+
+
+/**
+ * Handles the events on the element.
+ * @param {!goog.events.BrowserEvent} e The underlying browser event.
+ */
+goog.events.WheelHandler.prototype.handleEvent = function(e) {
+  var deltaMode = goog.events.WheelEvent.DeltaMode.PIXEL;
+  var deltaX = 0;
+  var deltaY = 0;
+  var deltaZ = 0;
+  var be = e.getBrowserEvent();
+  if (be.type == 'wheel') {
+    deltaMode = be.deltaMode;
+    deltaX = be.deltaX;
+    deltaY = be.deltaY;
+    deltaZ = be.deltaZ;
+  } else if (be.type == 'mousewheel') {
+    // Assume that these are still comparable to pixels. This may not be true
+    // for all old browsers.
+    if (goog.isDef(be.wheelDeltaX)) {
+      deltaX = -be.wheelDeltaX;
+      deltaY = -be.wheelDeltaY;
+    } else {
+      deltaY = -be.wheelDelta;
+    }
+  } else { // Historical Gecko
+    // Gecko returns multiple of 3 (representing the number of lines)
+    deltaMode = goog.events.WheelEvent.DeltaMode.LINE;
+    // Firefox 3.1 adds an axis field to the event to indicate axis.
+    if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) {
+      deltaX = be.detail;
+    } else {
+      deltaY = be.detail;
+    }
+  }
+  // For horizontal deltas we need to flip the value for RTL grids.
+  if (this.isRtl_) {
+    deltaX = -deltaX;
+  }
+  var newEvent = new goog.events.WheelEvent(
+      be, deltaMode, deltaX, deltaY, deltaZ);
+  this.dispatchEvent(newEvent);
+};
+
+
+/** @override */
+goog.events.WheelHandler.prototype.disposeInternal = function() {
+  goog.events.WheelHandler.superClass_.disposeInternal.call(this);
+  goog.events.unlistenByKey(this.listenKey_);
+  this.listenKey_ = null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/format/emailaddress.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/format/emailaddress.js b/externs/GCL/externs/goog/format/emailaddress.js
new file mode 100644
index 0000000..670bc33
--- /dev/null
+++ b/externs/GCL/externs/goog/format/emailaddress.js
@@ -0,0 +1,499 @@
+// 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 Provides functions to parse and manipulate email addresses.
+ *
+ */
+
+goog.provide('goog.format.EmailAddress');
+
+goog.require('goog.string');
+
+
+
+/**
+ * Formats an email address string for display, and allows for extraction of
+ * the individual components of the address.
+ * @param {string=} opt_address The email address.
+ * @param {string=} opt_name The name associated with the email address.
+ * @constructor
+ */
+goog.format.EmailAddress = function(opt_address, opt_name) {
+  /**
+   * The name or personal string associated with the address.
+   * @type {string}
+   * @private
+   */
+  this.name_ = opt_name || '';
+
+  /**
+   * The email address.
+   * @type {string}
+   * @protected
+   */
+  this.address = opt_address || '';
+};
+
+
+/**
+ * Match string for opening tokens.
+ * @type {string}
+ * @private
+ */
+goog.format.EmailAddress.OPENERS_ = '"<([';
+
+
+/**
+ * Match string for closing tokens.
+ * @type {string}
+ * @private
+ */
+goog.format.EmailAddress.CLOSERS_ = '">)]';
+
+
+/**
+ * Match string for characters that require display names to be quoted and are
+ * not address separators.
+ * @type {string}
+ * @const
+ * @package
+ */
+goog.format.EmailAddress.SPECIAL_CHARS = '()<>@:\\\".[]';
+
+
+/**
+ * Match string for address separators.
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.format.EmailAddress.ADDRESS_SEPARATORS_ = ',;';
+
+
+/**
+ * Match string for characters that, when in a display name, require it to be
+ * quoted.
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.format.EmailAddress.CHARS_REQUIRE_QUOTES_ =
+    goog.format.EmailAddress.SPECIAL_CHARS +
+    goog.format.EmailAddress.ADDRESS_SEPARATORS_;
+
+
+/**
+ * A RegExp to match all double quotes.  Used in cleanAddress().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ALL_DOUBLE_QUOTES_ = /\"/g;
+
+
+/**
+ * A RegExp to match escaped double quotes.  Used in parse().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ESCAPED_DOUBLE_QUOTES_ = /\\\"/g;
+
+
+/**
+ * A RegExp to match all backslashes.  Used in cleanAddress().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ALL_BACKSLASHES_ = /\\/g;
+
+
+/**
+ * A RegExp to match escaped backslashes.  Used in parse().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ESCAPED_BACKSLASHES_ = /\\\\/g;
+
+
+/**
+ * A string representing the RegExp for the local part of an email address.
+ * @private {string}
+ */
+goog.format.EmailAddress.LOCAL_PART_REGEXP_STR_ =
+    '[+a-zA-Z0-9_.!#$%&\'*\\/=?^`{|}~-]+';
+
+
+/**
+ * A string representing the RegExp for the domain part of an email address.
+ * @private {string}
+ */
+goog.format.EmailAddress.DOMAIN_PART_REGEXP_STR_ =
+    '([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9]{2,63}';
+
+
+/**
+ * A RegExp to match the local part of an email address.
+ * @private {!RegExp}
+ */
+goog.format.EmailAddress.LOCAL_PART_ =
+    new RegExp('^' + goog.format.EmailAddress.LOCAL_PART_REGEXP_STR_ + '$');
+
+
+/**
+ * A RegExp to match the domain part of an email address.
+ * @private {!RegExp}
+ */
+goog.format.EmailAddress.DOMAIN_PART_ =
+    new RegExp('^' + goog.format.EmailAddress.DOMAIN_PART_REGEXP_STR_ + '$');
+
+
+/**
+ * A RegExp to match an email address.
+ * @private {!RegExp}
+ */
+goog.format.EmailAddress.EMAIL_ADDRESS_ =
+    new RegExp('^' + goog.format.EmailAddress.LOCAL_PART_REGEXP_STR_ + '@' +
+        goog.format.EmailAddress.DOMAIN_PART_REGEXP_STR_ + '$');
+
+
+/**
+ * Get the name associated with the email address.
+ * @return {string} The name or personal portion of the address.
+ * @final
+ */
+goog.format.EmailAddress.prototype.getName = function() {
+  return this.name_;
+};
+
+
+/**
+ * Get the email address.
+ * @return {string} The email address.
+ * @final
+ */
+goog.format.EmailAddress.prototype.getAddress = function() {
+  return this.address;
+};
+
+
+/**
+ * Set the name associated with the email address.
+ * @param {string} name The name to associate.
+ * @final
+ */
+goog.format.EmailAddress.prototype.setName = function(name) {
+  this.name_ = name;
+};
+
+
+/**
+ * Set the email address.
+ * @param {string} address The email address.
+ * @final
+ */
+goog.format.EmailAddress.prototype.setAddress = function(address) {
+  this.address = address;
+};
+
+
+/**
+ * Return the address in a standard format:
+ *  - remove extra spaces.
+ *  - Surround name with quotes if it contains special characters.
+ * @return {string} The cleaned address.
+ * @override
+ */
+goog.format.EmailAddress.prototype.toString = function() {
+  return this.toStringInternal(
+      goog.format.EmailAddress.CHARS_REQUIRE_QUOTES_);
+};
+
+
+/**
+ * Check if a display name requires quoting.
+ * @param {string} name The display name
+ * @param {string} specialChars String that contains the characters that require
+ *  the display name to be quoted. This may change based in whereas we are
+ *  in EAI context or not.
+ * @return {boolean}
+ * @private
+ */
+goog.format.EmailAddress.isQuoteNeeded_ = function(name, specialChars) {
+  for (var i = 0; i < specialChars.length; i++) {
+    var specialChar = specialChars[i];
+    if (goog.string.contains(name, specialChar)) {
+      return true;
+    }
+  }
+  return false;
+};
+
+
+/**
+ * Return the address in a standard format:
+ *  - remove extra spaces.
+ *  - Surround name with quotes if it contains special characters.
+ * @param {string} specialChars String that contains the characters that require
+ *  the display name to be quoted.
+ * @return {string} The cleaned address.
+ * @protected
+ */
+goog.format.EmailAddress.prototype.toStringInternal = function(specialChars) {
+  var name = this.getName();
+
+  // We intentionally remove double quotes in the name because escaping
+  // them to \" looks ugly.
+  name = name.replace(goog.format.EmailAddress.ALL_DOUBLE_QUOTES_, '');
+
+  // If the name has special characters, we need to quote it and escape \'s.
+  if (goog.format.EmailAddress.isQuoteNeeded_(name, specialChars)) {
+    name = '"' +
+        name.replace(goog.format.EmailAddress.ALL_BACKSLASHES_, '\\\\') + '"';
+  }
+
+  if (name == '') {
+    return this.address;
+  }
+  if (this.address == '') {
+    return name;
+  }
+  return name + ' <' + this.address + '>';
+};
+
+
+/**
+ * Determines is the current object is a valid email address.
+ * @return {boolean} Whether the email address is valid.
+ */
+goog.format.EmailAddress.prototype.isValid = function() {
+  return goog.format.EmailAddress.isValidAddrSpec(this.address);
+};
+
+
+/**
+ * Checks if the provided string is a valid email address. Supports both
+ * simple email addresses (address specs) and addresses that contain display
+ * names.
+ * @param {string} str The email address to check.
+ * @return {boolean} Whether the provided string is a valid address.
+ */
+goog.format.EmailAddress.isValidAddress = function(str) {
+  return goog.format.EmailAddress.parse(str).isValid();
+};
+
+
+/**
+ * Checks if the provided string is a valid address spec (local@domain.com).
+ * @param {string} str The email address to check.
+ * @return {boolean} Whether the provided string is a valid address spec.
+ */
+goog.format.EmailAddress.isValidAddrSpec = function(str) {
+  // This is a fairly naive implementation, but it covers 99% of use cases.
+  // For more details, see http://en.wikipedia.org/wiki/Email_address#Syntax
+  return goog.format.EmailAddress.EMAIL_ADDRESS_.test(str);
+};
+
+
+/**
+ * Checks if the provided string is a valid local part (part before the '@') of
+ * an email address.
+ * @param {string} str The local part to check.
+ * @return {boolean} Whether the provided string is a valid local part.
+ */
+goog.format.EmailAddress.isValidLocalPartSpec = function(str) {
+  return goog.format.EmailAddress.LOCAL_PART_.test(str);
+};
+
+
+/**
+ * Checks if the provided string is a valid domain part (part after the '@') of
+ * an email address.
+ * @param {string} str The domain part to check.
+ * @return {boolean} Whether the provided string is a valid domain part.
+ */
+goog.format.EmailAddress.isValidDomainPartSpec = function(str) {
+  return goog.format.EmailAddress.DOMAIN_PART_.test(str);
+};
+
+
+/**
+ * Parses an email address of the form "name" &lt;address&gt; ("name" is
+ * optional) into an email address.
+ * @param {string} addr The address string.
+ * @param {function(new: goog.format.EmailAddress, string=,string=)} ctor
+ *     EmailAddress constructor to instantiate the output address.
+ * @return {!goog.format.EmailAddress} The parsed address.
+ * @protected
+ */
+goog.format.EmailAddress.parseInternal = function(addr, ctor) {
+  // TODO(ecattell): Strip bidi markers.
+  var name = '';
+  var address = '';
+  for (var i = 0; i < addr.length;) {
+    var token = goog.format.EmailAddress.getToken_(addr, i);
+    if (token.charAt(0) == '<' && token.indexOf('>') != -1) {
+      var end = token.indexOf('>');
+      address = token.substring(1, end);
+    } else if (address == '') {
+      name += token;
+    }
+    i += token.length;
+  }
+
+  // Check if it's a simple email address of the form "jlim@google.com".
+  if (address == '' && name.indexOf('@') != -1) {
+    address = name;
+    name = '';
+  }
+
+  name = goog.string.collapseWhitespace(name);
+  name = goog.string.stripQuotes(name, '\'');
+  name = goog.string.stripQuotes(name, '"');
+  // Replace escaped quotes and slashes.
+  name = name.replace(goog.format.EmailAddress.ESCAPED_DOUBLE_QUOTES_, '"');
+  name = name.replace(goog.format.EmailAddress.ESCAPED_BACKSLASHES_, '\\');
+  address = goog.string.collapseWhitespace(address);
+  return new ctor(address, name);
+};
+
+
+/**
+ * Parses an email address of the form "name" &lt;address&gt; into
+ * an email address.
+ * @param {string} addr The address string.
+ * @return {!goog.format.EmailAddress} The parsed address.
+ */
+goog.format.EmailAddress.parse = function(addr) {
+  return goog.format.EmailAddress.parseInternal(
+      addr, goog.format.EmailAddress);
+};
+
+
+/**
+ * Parse a string containing email addresses of the form
+ * "name" &lt;address&gt; into an array of email addresses.
+ * @param {string} str The address list.
+ * @param {function(string)} parser The parser to employ.
+ * @param {function(string):boolean} separatorChecker Accepts a character and
+ *    returns whether it should be considered an address separator.
+ * @return {!Array<!goog.format.EmailAddress>} The parsed emails.
+ * @protected
+ */
+goog.format.EmailAddress.parseListInternal = function(
+    str, parser, separatorChecker) {
+  var result = [];
+  var email = '';
+  var token;
+
+  // Remove non-UNIX-style newlines that would otherwise cause getToken_ to
+  // choke. Remove multiple consecutive whitespace characters for the same
+  // reason.
+  str = goog.string.collapseWhitespace(str);
+
+  for (var i = 0; i < str.length; ) {
+    token = goog.format.EmailAddress.getToken_(str, i);
+    if (separatorChecker(token) ||
+        (token == ' ' && parser(email).isValid())) {
+      if (!goog.string.isEmptyOrWhitespace(email)) {
+        result.push(parser(email));
+      }
+      email = '';
+      i++;
+      continue;
+    }
+    email += token;
+    i += token.length;
+  }
+
+  // Add the final token.
+  if (!goog.string.isEmptyOrWhitespace(email)) {
+    result.push(parser(email));
+  }
+  return result;
+};
+
+
+/**
+ * Parses a string containing email addresses of the form
+ * "name" &lt;address&gt; into an array of email addresses.
+ * @param {string} str The address list.
+ * @return {!Array<!goog.format.EmailAddress>} The parsed emails.
+ */
+goog.format.EmailAddress.parseList = function(str) {
+  return goog.format.EmailAddress.parseListInternal(
+      str, goog.format.EmailAddress.parse,
+      goog.format.EmailAddress.isAddressSeparator);
+};
+
+
+/**
+ * Get the next token from a position in an address string.
+ * @param {string} str the string.
+ * @param {number} pos the position.
+ * @return {string} the token.
+ * @private
+ */
+goog.format.EmailAddress.getToken_ = function(str, pos) {
+  var ch = str.charAt(pos);
+  var p = goog.format.EmailAddress.OPENERS_.indexOf(ch);
+  if (p == -1) {
+    return ch;
+  }
+  if (goog.format.EmailAddress.isEscapedDlQuote_(str, pos)) {
+
+    // If an opener is an escaped quote we do not treat it as a real opener
+    // and keep accumulating the token.
+    return ch;
+  }
+  var closerChar = goog.format.EmailAddress.CLOSERS_.charAt(p);
+  var endPos = str.indexOf(closerChar, pos + 1);
+
+  // If the closer is a quote we go forward skipping escaped quotes until we
+  // hit the real closing one.
+  while (endPos >= 0 &&
+         goog.format.EmailAddress.isEscapedDlQuote_(str, endPos)) {
+    endPos = str.indexOf(closerChar, endPos + 1);
+  }
+  var token = (endPos >= 0) ? str.substring(pos, endPos + 1) : ch;
+  return token;
+};
+
+
+/**
+ * Checks if the character in the current position is an escaped double quote
+ * ( \" ).
+ * @param {string} str the string.
+ * @param {number} pos the position.
+ * @return {boolean} true if the char is escaped double quote.
+ * @private
+ */
+goog.format.EmailAddress.isEscapedDlQuote_ = function(str, pos) {
+  if (str.charAt(pos) != '"') {
+    return false;
+  }
+  var slashCount = 0;
+  for (var idx = pos - 1; idx >= 0 && str.charAt(idx) == '\\'; idx--) {
+    slashCount++;
+  }
+  return ((slashCount % 2) != 0);
+};
+
+
+/**
+ * @param {string} ch The character to test.
+ * @return {boolean} Whether the provided character is an address separator.
+ */
+goog.format.EmailAddress.isAddressSeparator = function(ch) {
+  return goog.string.contains(goog.format.EmailAddress.ADDRESS_SEPARATORS_, ch);
+};


Mime
View raw message