You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ft...@apache.org on 2015/09/17 17:28:46 UTC

[31/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/classlist.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/classlist.js b/externs/GCL/externs/goog/dom/classlist.js
new file mode 100644
index 0000000..dcbb7ed
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/classlist.js
@@ -0,0 +1,277 @@
+// 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 Utilities for detecting, adding and removing classes.  Prefer
+ * this over goog.dom.classes for new code since it attempts to use classList
+ * (DOMTokenList: http://dom.spec.whatwg.org/#domtokenlist) which is faster
+ * and requires less code.
+ *
+ * Note: these utilities are meant to operate on HTMLElements
+ * and may have unexpected behavior on elements with differing interfaces
+ * (such as SVGElements).
+ */
+
+
+goog.provide('goog.dom.classlist');
+
+goog.require('goog.array');
+
+
+/**
+ * Override this define at build-time if you know your target supports it.
+ * @define {boolean} Whether to use the classList property (DOMTokenList).
+ */
+goog.define('goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST', false);
+
+
+/**
+ * Gets an array-like object of class names on an element.
+ * @param {Element} element DOM node to get the classes of.
+ * @return {!goog.array.ArrayLike} Class names on {@code element}.
+ */
+goog.dom.classlist.get = function(element) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    return element.classList;
+  }
+
+  var className = element.className;
+  // Some types of elements don't have a className in IE (e.g. iframes).
+  // Furthermore, in Firefox, className is not a string when the element is
+  // an SVG element.
+  return goog.isString(className) && className.match(/\S+/g) || [];
+};
+
+
+/**
+ * Sets the entire class name of an element.
+ * @param {Element} element DOM node to set class of.
+ * @param {string} className Class name(s) to apply to element.
+ */
+goog.dom.classlist.set = function(element, className) {
+  element.className = className;
+};
+
+
+/**
+ * Returns true if an element has a class.  This method may throw a DOM
+ * exception for an invalid or empty class name if DOMTokenList is used.
+ * @param {Element} element DOM node to test.
+ * @param {string} className Class name to test for.
+ * @return {boolean} Whether element has the class.
+ */
+goog.dom.classlist.contains = function(element, className) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    return element.classList.contains(className);
+  }
+  return goog.array.contains(goog.dom.classlist.get(element), className);
+};
+
+
+/**
+ * Adds a class to an element.  Does not add multiples of class names.  This
+ * method may throw a DOM exception for an invalid or empty class name if
+ * DOMTokenList is used.
+ * @param {Element} element DOM node to add class to.
+ * @param {string} className Class name to add.
+ */
+goog.dom.classlist.add = function(element, className) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    element.classList.add(className);
+    return;
+  }
+
+  if (!goog.dom.classlist.contains(element, className)) {
+    // Ensure we add a space if this is not the first class name added.
+    element.className += element.className.length > 0 ?
+        (' ' + className) : className;
+  }
+};
+
+
+/**
+ * Convenience method to add a number of class names at once.
+ * @param {Element} element The element to which to add classes.
+ * @param {goog.array.ArrayLike<string>} classesToAdd An array-like object
+ * containing a collection of class names to add to the element.
+ * This method may throw a DOM exception if classesToAdd contains invalid
+ * or empty class names.
+ */
+goog.dom.classlist.addAll = function(element, classesToAdd) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    goog.array.forEach(classesToAdd, function(className) {
+      goog.dom.classlist.add(element, className);
+    });
+    return;
+  }
+
+  var classMap = {};
+
+  // Get all current class names into a map.
+  goog.array.forEach(goog.dom.classlist.get(element),
+      function(className) {
+        classMap[className] = true;
+      });
+
+  // Add new class names to the map.
+  goog.array.forEach(classesToAdd,
+      function(className) {
+        classMap[className] = true;
+      });
+
+  // Flatten the keys of the map into the className.
+  element.className = '';
+  for (var className in classMap) {
+    element.className += element.className.length > 0 ?
+        (' ' + className) : className;
+  }
+};
+
+
+/**
+ * Removes a class from an element.  This method may throw a DOM exception
+ * for an invalid or empty class name if DOMTokenList is used.
+ * @param {Element} element DOM node to remove class from.
+ * @param {string} className Class name to remove.
+ */
+goog.dom.classlist.remove = function(element, className) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    element.classList.remove(className);
+    return;
+  }
+
+  if (goog.dom.classlist.contains(element, className)) {
+    // Filter out the class name.
+    element.className = goog.array.filter(
+        goog.dom.classlist.get(element),
+        function(c) {
+          return c != className;
+        }).join(' ');
+  }
+};
+
+
+/**
+ * Removes a set of classes from an element.  Prefer this call to
+ * repeatedly calling {@code goog.dom.classlist.remove} if you want to remove
+ * a large set of class names at once.
+ * @param {Element} element The element from which to remove classes.
+ * @param {goog.array.ArrayLike<string>} classesToRemove An array-like object
+ * containing a collection of class names to remove from the element.
+ * This method may throw a DOM exception if classesToRemove contains invalid
+ * or empty class names.
+ */
+goog.dom.classlist.removeAll = function(element, classesToRemove) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    goog.array.forEach(classesToRemove, function(className) {
+      goog.dom.classlist.remove(element, className);
+    });
+    return;
+  }
+  // Filter out those classes in classesToRemove.
+  element.className = goog.array.filter(
+      goog.dom.classlist.get(element),
+      function(className) {
+        // If this class is not one we are trying to remove,
+        // add it to the array of new class names.
+        return !goog.array.contains(classesToRemove, className);
+      }).join(' ');
+};
+
+
+/**
+ * Adds or removes a class depending on the enabled argument.  This method
+ * may throw a DOM exception for an invalid or empty class name if DOMTokenList
+ * is used.
+ * @param {Element} element DOM node to add or remove the class on.
+ * @param {string} className Class name to add or remove.
+ * @param {boolean} enabled Whether to add or remove the class (true adds,
+ *     false removes).
+ */
+goog.dom.classlist.enable = function(element, className, enabled) {
+  if (enabled) {
+    goog.dom.classlist.add(element, className);
+  } else {
+    goog.dom.classlist.remove(element, className);
+  }
+};
+
+
+/**
+ * Adds or removes a set of classes depending on the enabled argument.  This
+ * method may throw a DOM exception for an invalid or empty class name if
+ * DOMTokenList is used.
+ * @param {!Element} element DOM node to add or remove the class on.
+ * @param {goog.array.ArrayLike<string>} classesToEnable An array-like object
+ *     containing a collection of class names to add or remove from the element.
+ * @param {boolean} enabled Whether to add or remove the classes (true adds,
+ *     false removes).
+ */
+goog.dom.classlist.enableAll = function(element, classesToEnable, enabled) {
+  var f = enabled ? goog.dom.classlist.addAll :
+      goog.dom.classlist.removeAll;
+  f(element, classesToEnable);
+};
+
+
+/**
+ * Switches a class on an element from one to another without disturbing other
+ * classes. If the fromClass isn't removed, the toClass won't be added.  This
+ * method may throw a DOM exception if the class names are empty or invalid.
+ * @param {Element} element DOM node to swap classes on.
+ * @param {string} fromClass Class to remove.
+ * @param {string} toClass Class to add.
+ * @return {boolean} Whether classes were switched.
+ */
+goog.dom.classlist.swap = function(element, fromClass, toClass) {
+  if (goog.dom.classlist.contains(element, fromClass)) {
+    goog.dom.classlist.remove(element, fromClass);
+    goog.dom.classlist.add(element, toClass);
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * Removes a class if an element has it, and adds it the element doesn't have
+ * it.  Won't affect other classes on the node.  This method may throw a DOM
+ * exception if the class name is empty or invalid.
+ * @param {Element} element DOM node to toggle class on.
+ * @param {string} className Class to toggle.
+ * @return {boolean} True if class was added, false if it was removed
+ *     (in other words, whether element has the class after this function has
+ *     been called).
+ */
+goog.dom.classlist.toggle = function(element, className) {
+  var add = !goog.dom.classlist.contains(element, className);
+  goog.dom.classlist.enable(element, className, add);
+  return add;
+};
+
+
+/**
+ * Adds and removes a class of an element.  Unlike
+ * {@link goog.dom.classlist.swap}, this method adds the classToAdd regardless
+ * of whether the classToRemove was present and had been removed.  This method
+ * may throw a DOM exception if the class names are empty or invalid.
+ *
+ * @param {Element} element DOM node to swap classes on.
+ * @param {string} classToRemove Class to remove.
+ * @param {string} classToAdd Class to add.
+ */
+goog.dom.classlist.addRemove = function(element, classToRemove, classToAdd) {
+  goog.dom.classlist.remove(element, classToRemove);
+  goog.dom.classlist.add(element, classToAdd);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/controlrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/controlrange.js b/externs/GCL/externs/goog/dom/controlrange.js
new file mode 100644
index 0000000..61df59a
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/controlrange.js
@@ -0,0 +1,494 @@
+// 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 Utilities for working with IE control ranges.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.ControlRange');
+goog.provide('goog.dom.ControlRangeIterator');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.AbstractMultiRange');
+goog.require('goog.dom.AbstractRange');
+goog.require('goog.dom.RangeIterator');
+goog.require('goog.dom.RangeType');
+goog.require('goog.dom.SavedRange');
+goog.require('goog.dom.TagWalkType');
+goog.require('goog.dom.TextRange');
+goog.require('goog.iter.StopIteration');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Create a new control selection with no properties.  Do not use this
+ * constructor: use one of the goog.dom.Range.createFrom* methods instead.
+ * @constructor
+ * @extends {goog.dom.AbstractMultiRange}
+ * @final
+ */
+goog.dom.ControlRange = function() {
+  /**
+   * The IE control range obejct.
+   * @private {Object}
+   */
+  this.range_ = null;
+
+  /**
+   * Cached list of elements.
+   * @private {Array<Element>}
+   */
+  this.elements_ = null;
+
+  /**
+   * Cached sorted list of elements.
+   * @private {Array<Element>}
+   */
+  this.sortedElements_ = null;
+};
+goog.inherits(goog.dom.ControlRange, goog.dom.AbstractMultiRange);
+
+
+/**
+ * Create a new range wrapper from the given browser range object.  Do not use
+ * this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Object} controlRange The browser range object.
+ * @return {!goog.dom.ControlRange} A range wrapper object.
+ */
+goog.dom.ControlRange.createFromBrowserRange = function(controlRange) {
+  var range = new goog.dom.ControlRange();
+  range.range_ = controlRange;
+  return range;
+};
+
+
+/**
+ * Create a new range wrapper that selects the given element.  Do not use
+ * this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {...Element} var_args The element(s) to select.
+ * @return {!goog.dom.ControlRange} A range wrapper object.
+ */
+goog.dom.ControlRange.createFromElements = function(var_args) {
+  var range = goog.dom.getOwnerDocument(arguments[0]).body.createControlRange();
+  for (var i = 0, len = arguments.length; i < len; i++) {
+    range.addElement(arguments[i]);
+  }
+  return goog.dom.ControlRange.createFromBrowserRange(range);
+};
+
+
+// Method implementations
+
+
+/**
+ * Clear cached values.
+ * @private
+ */
+goog.dom.ControlRange.prototype.clearCachedValues_ = function() {
+  this.elements_ = null;
+  this.sortedElements_ = null;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.clone = function() {
+  return goog.dom.ControlRange.createFromElements.apply(this,
+                                                        this.getElements());
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getType = function() {
+  return goog.dom.RangeType.CONTROL;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getBrowserRangeObject = function() {
+  return this.range_ || document.body.createControlRange();
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.setBrowserRangeObject = function(nativeRange) {
+  if (!goog.dom.AbstractRange.isNativeControlRange(nativeRange)) {
+    return false;
+  }
+  this.range_ = nativeRange;
+  return true;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getTextRangeCount = function() {
+  return this.range_ ? this.range_.length : 0;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getTextRange = function(i) {
+  return goog.dom.TextRange.createFromNodeContents(this.range_.item(i));
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getContainer = function() {
+  return goog.dom.findCommonAncestor.apply(null, this.getElements());
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getStartNode = function() {
+  return this.getSortedElements()[0];
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getStartOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getEndNode = function() {
+  var sorted = this.getSortedElements();
+  var startsLast = /** @type {Node} */ (goog.array.peek(sorted));
+  return /** @type {Node} */ (goog.array.find(sorted, function(el) {
+    return goog.dom.contains(el, startsLast);
+  }));
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getEndOffset = function() {
+  return this.getEndNode().childNodes.length;
+};
+
+
+// TODO(robbyw): Figure out how to unify getElements with TextRange API.
+/**
+ * @return {!Array<Element>} Array of elements in the control range.
+ */
+goog.dom.ControlRange.prototype.getElements = function() {
+  if (!this.elements_) {
+    this.elements_ = [];
+    if (this.range_) {
+      for (var i = 0; i < this.range_.length; i++) {
+        this.elements_.push(this.range_.item(i));
+      }
+    }
+  }
+
+  return this.elements_;
+};
+
+
+/**
+ * @return {!Array<Element>} Array of elements comprising the control range,
+ *     sorted by document order.
+ */
+goog.dom.ControlRange.prototype.getSortedElements = function() {
+  if (!this.sortedElements_) {
+    this.sortedElements_ = this.getElements().concat();
+    this.sortedElements_.sort(function(a, b) {
+      return a.sourceIndex - b.sourceIndex;
+    });
+  }
+
+  return this.sortedElements_;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.isRangeInDocument = function() {
+  var returnValue = false;
+
+  try {
+    returnValue = goog.array.every(this.getElements(), function(element) {
+      // On IE, this throws an exception when the range is detached.
+      return goog.userAgent.IE ?
+          !!element.parentNode :
+          goog.dom.contains(element.ownerDocument.body, element);
+    });
+  } catch (e) {
+    // IE sometimes throws Invalid Argument errors for detached elements.
+    // Note: trying to return a value from the above try block can cause IE
+    // to crash.  It is necessary to use the local returnValue.
+  }
+
+  return returnValue;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.isCollapsed = function() {
+  return !this.range_ || !this.range_.length;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getText = function() {
+  // TODO(robbyw): What about for table selections?  Should those have text?
+  return '';
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getHtmlFragment = function() {
+  return goog.array.map(this.getSortedElements(), goog.dom.getOuterHtml).
+      join('');
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getValidHtml = function() {
+  return this.getHtmlFragment();
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getPastableHtml =
+    goog.dom.ControlRange.prototype.getValidHtml;
+
+
+/** @override */
+goog.dom.ControlRange.prototype.__iterator__ = function(opt_keys) {
+  return new goog.dom.ControlRangeIterator(this);
+};
+
+
+// RANGE ACTIONS
+
+
+/** @override */
+goog.dom.ControlRange.prototype.select = function() {
+  if (this.range_) {
+    this.range_.select();
+  }
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.removeContents = function() {
+  // TODO(robbyw): Test implementing with execCommand('Delete')
+  if (this.range_) {
+    var nodes = [];
+    for (var i = 0, len = this.range_.length; i < len; i++) {
+      nodes.push(this.range_.item(i));
+    }
+    goog.array.forEach(nodes, goog.dom.removeNode);
+
+    this.collapse(false);
+  }
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.replaceContentsWithNode = function(node) {
+  // Control selections have to have the node inserted before removing the
+  // selection contents because a collapsed control range doesn't have start or
+  // end nodes.
+  var result = this.insertNode(node, true);
+
+  if (!this.isCollapsed()) {
+    this.removeContents();
+  }
+
+  return result;
+};
+
+
+// SAVE/RESTORE
+
+
+/** @override */
+goog.dom.ControlRange.prototype.saveUsingDom = function() {
+  return new goog.dom.DomSavedControlRange_(this);
+};
+
+
+// RANGE MODIFICATION
+
+
+/** @override */
+goog.dom.ControlRange.prototype.collapse = function(toAnchor) {
+  // TODO(robbyw): Should this return a text range?  If so, API needs to change.
+  this.range_ = null;
+  this.clearCachedValues_();
+};
+
+
+// SAVED RANGE OBJECTS
+
+
+
+/**
+ * A SavedRange implementation using DOM endpoints.
+ * @param {goog.dom.ControlRange} range The range to save.
+ * @constructor
+ * @extends {goog.dom.SavedRange}
+ * @private
+ */
+goog.dom.DomSavedControlRange_ = function(range) {
+  /**
+   * The element list.
+   * @type {Array<Element>}
+   * @private
+   */
+  this.elements_ = range.getElements();
+};
+goog.inherits(goog.dom.DomSavedControlRange_, goog.dom.SavedRange);
+
+
+/** @override */
+goog.dom.DomSavedControlRange_.prototype.restoreInternal = function() {
+  var doc = this.elements_.length ?
+      goog.dom.getOwnerDocument(this.elements_[0]) : document;
+  var controlRange = doc.body.createControlRange();
+  for (var i = 0, len = this.elements_.length; i < len; i++) {
+    controlRange.addElement(this.elements_[i]);
+  }
+  return goog.dom.ControlRange.createFromBrowserRange(controlRange);
+};
+
+
+/** @override */
+goog.dom.DomSavedControlRange_.prototype.disposeInternal = function() {
+  goog.dom.DomSavedControlRange_.superClass_.disposeInternal.call(this);
+  delete this.elements_;
+};
+
+
+// RANGE ITERATION
+
+
+
+/**
+ * Subclass of goog.dom.TagIterator that iterates over a DOM range.  It
+ * adds functions to determine the portion of each text node that is selected.
+ *
+ * @param {goog.dom.ControlRange?} range The range to traverse.
+ * @constructor
+ * @extends {goog.dom.RangeIterator}
+ * @final
+ */
+goog.dom.ControlRangeIterator = function(range) {
+  /**
+   * The first node in the selection.
+   * @private {Node}
+   */
+  this.startNode_ = null;
+
+  /**
+   * The last node in the selection.
+   * @private {Node}
+   */
+  this.endNode_ = null;
+
+  /**
+   * The list of elements left to traverse.
+   * @private {Array<Element>?}
+   */
+  this.elements_ = null;
+
+  if (range) {
+    this.elements_ = range.getSortedElements();
+    this.startNode_ = this.elements_.shift();
+    this.endNode_ = /** @type {Node} */ (goog.array.peek(this.elements_)) ||
+        this.startNode_;
+  }
+
+  goog.dom.ControlRangeIterator.base(
+      this, 'constructor', this.startNode_, false);
+};
+goog.inherits(goog.dom.ControlRangeIterator, goog.dom.RangeIterator);
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getStartTextOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getEndTextOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getStartNode = function() {
+  return this.startNode_;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getEndNode = function() {
+  return this.endNode_;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.isLast = function() {
+  return !this.depth && !this.elements_.length;
+};
+
+
+/**
+ * Move to the next position in the selection.
+ * Throws {@code goog.iter.StopIteration} when it passes the end of the range.
+ * @return {Node} The node at the next position.
+ * @override
+ */
+goog.dom.ControlRangeIterator.prototype.next = function() {
+  // Iterate over each element in the range, and all of its children.
+  if (this.isLast()) {
+    throw goog.iter.StopIteration;
+  } else if (!this.depth) {
+    var el = this.elements_.shift();
+    this.setPosition(el,
+                     goog.dom.TagWalkType.START_TAG,
+                     goog.dom.TagWalkType.START_TAG);
+    return el;
+  }
+
+  // Call the super function.
+  return goog.dom.ControlRangeIterator.superClass_.next.call(this);
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.copyFrom = function(other) {
+  this.elements_ = other.elements_;
+  this.startNode_ = other.startNode_;
+  this.endNode_ = other.endNode_;
+
+  goog.dom.ControlRangeIterator.superClass_.copyFrom.call(this, other);
+};
+
+
+/**
+ * @return {!goog.dom.ControlRangeIterator} An identical iterator.
+ * @override
+ */
+goog.dom.ControlRangeIterator.prototype.clone = function() {
+  var copy = new goog.dom.ControlRangeIterator(null);
+  copy.copyFrom(this);
+  return copy;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/dataset.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/dataset.js b/externs/GCL/externs/goog/dom/dataset.js
new file mode 100644
index 0000000..6f24587
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/dataset.js
@@ -0,0 +1,154 @@
+// 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 Utilities for adding, removing and setting values in
+ * an Element's dataset.
+ * See {@link http://www.w3.org/TR/html5/Overview.html#dom-dataset}.
+ *
+ * @author nicksay@google.com (Alex Nicksay)
+ */
+
+goog.provide('goog.dom.dataset');
+
+goog.require('goog.string');
+goog.require('goog.userAgent.product');
+
+
+/**
+ * Whether using the dataset property is allowed.  In IE (up to and including
+ * IE 11), setting element.dataset in JS does not propagate values to CSS,
+ * breaking expressions such as `content: attr(data-content)` that would
+ * otherwise work.
+ * See {@link https://github.com/google/closure-library/issues/396}.
+ * @const
+ * @private
+ */
+goog.dom.dataset.ALLOWED_ = !goog.userAgent.product.IE;
+
+
+/**
+ * The DOM attribute name prefix that must be present for it to be considered
+ * for a dataset.
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.dom.dataset.PREFIX_ = 'data-';
+
+
+/**
+ * Sets a custom data attribute on an element. The key should be
+ * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ * @param {Element} element DOM node to set the custom data attribute on.
+ * @param {string} key Key for the custom data attribute.
+ * @param {string} value Value for the custom data attribute.
+ */
+goog.dom.dataset.set = function(element, key, value) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    element.dataset[key] = value;
+  } else {
+    element.setAttribute(
+        goog.dom.dataset.PREFIX_ + goog.string.toSelectorCase(key),
+        value);
+  }
+};
+
+
+/**
+ * Gets a custom data attribute from an element. The key should be
+ * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ * @param {Element} element DOM node to get the custom data attribute from.
+ * @param {string} key Key for the custom data attribute.
+ * @return {?string} The attribute value, if it exists.
+ */
+goog.dom.dataset.get = function(element, key) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    // Android browser (non-chrome) returns the empty string for
+    // element.dataset['doesNotExist'].
+    if (!(key in element.dataset)) {
+      return null;
+    }
+    return element.dataset[key];
+  } else {
+    return element.getAttribute(goog.dom.dataset.PREFIX_ +
+                                goog.string.toSelectorCase(key));
+  }
+};
+
+
+/**
+ * Removes a custom data attribute from an element. The key should be
+  * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ * @param {Element} element DOM node to get the custom data attribute from.
+ * @param {string} key Key for the custom data attribute.
+ */
+goog.dom.dataset.remove = function(element, key) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    delete element.dataset[key];
+  } else {
+    element.removeAttribute(goog.dom.dataset.PREFIX_ +
+                            goog.string.toSelectorCase(key));
+  }
+};
+
+
+/**
+ * Checks whether custom data attribute exists on an element. The key should be
+ * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ *
+ * @param {Element} element DOM node to get the custom data attribute from.
+ * @param {string} key Key for the custom data attribute.
+ * @return {boolean} Whether the attribute exists.
+ */
+goog.dom.dataset.has = function(element, key) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    return key in element.dataset;
+  } else if (element.hasAttribute) {
+    return element.hasAttribute(goog.dom.dataset.PREFIX_ +
+                                goog.string.toSelectorCase(key));
+  } else {
+    return !!(element.getAttribute(goog.dom.dataset.PREFIX_ +
+                                   goog.string.toSelectorCase(key)));
+  }
+};
+
+
+/**
+ * Gets all custom data attributes as a string map.  The attribute names will be
+ * camel cased (e.g., data-foo-bar -> dataset['fooBar']).  This operation is not
+ * safe for attributes having camel-cased names clashing with already existing
+ * properties (e.g., data-to-string -> dataset['toString']).
+ * @param {!Element} element DOM node to get the data attributes from.
+ * @return {!Object} The string map containing data attributes and their
+ *     respective values.
+ */
+goog.dom.dataset.getAll = function(element) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    return element.dataset;
+  } else {
+    var dataset = {};
+    var attributes = element.attributes;
+    for (var i = 0; i < attributes.length; ++i) {
+      var attribute = attributes[i];
+      if (goog.string.startsWith(attribute.name,
+                                 goog.dom.dataset.PREFIX_)) {
+        // We use substr(5), since it's faster than replacing 'data-' with ''.
+        var key = goog.string.toCamelCase(attribute.name.substr(5));
+        dataset[key] = attribute.value;
+      }
+    }
+    return dataset;
+  }
+};