From 2b4757367470d8e36bc00901dac567e375796ed4 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Tue, 13 Nov 2018 00:24:09 -0500 Subject: update viz 2 to use the newest version, which has some performance improvements and is easier to read the code for. also update the description --- assets/viz/2/goog/dom/dom.js | 459 +++++++++++++++++++++++++++++++++---------- 1 file changed, 350 insertions(+), 109 deletions(-) (limited to 'assets/viz/2/goog/dom/dom.js') diff --git a/assets/viz/2/goog/dom/dom.js b/assets/viz/2/goog/dom/dom.js index 4d3cdf9..919a0b6 100644 --- a/assets/viz/2/goog/dom/dom.js +++ b/assets/viz/2/goog/dom/dom.js @@ -170,6 +170,24 @@ goog.dom.getRequiredElementHelper_ = function(doc, id) { goog.dom.$ = goog.dom.getElement; +/** + * Gets elements by tag name. + * @param {!goog.dom.TagName} tagName + * @param {(!Document|!Element)=} opt_parent Parent element or document where to + * look for elements. Defaults to document. + * @return {!NodeList} List of elements. The members of the list are + * {!Element} if tagName is not a member of goog.dom.TagName or more + * specific types if it is (e.g. {!HTMLAnchorElement} for + * goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: + */ +goog.dom.getElementsByTagName = function(tagName, opt_parent) { + var parent = opt_parent || document; + return parent.getElementsByTagName(String(tagName)); +}; + + /** * Looks up elements by both tag and class name, using browser native functions * ({@code querySelectorAll}, {@code getElementsByTagName} or @@ -189,11 +207,16 @@ goog.dom.$ = goog.dom.getElement; * * @see {goog.dom.query} * - * @param {?string=} opt_tag Element tag name. + * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name. * @param {?string=} opt_class Optional class name. * @param {(Document|Element)=} opt_el Optional element to look in. - * @return {!IArrayLike} Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). + * @return {!IArrayLike} Array-like list of elements (only a length property + * and numerical indices are guaranteed to exist). The members of the array + * are {!Element} if opt_tag is not a member of goog.dom.TagName or more + * specific types if it is (e.g. {!HTMLAnchorElement} for + * goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: */ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) { return goog.dom.getElementsByTagNameAndClass_( @@ -201,6 +224,24 @@ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) { }; +/** + * Gets the first element matching the tag and the class. + * + * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name. + * @param {?string=} opt_class Optional class name. + * @param {(Document|Element)=} opt_el Optional element to look in. + * @return {?R} Reference to a DOM node. The return type is {?Element} if + * tagName is a string or a more specific type if it is a member of + * goog.dom.TagName (e.g. {?HTMLAnchorElement} for goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: + */ +goog.dom.getElementByTagNameAndClass = function(opt_tag, opt_class, opt_el) { + return goog.dom.getElementByTagNameAndClass_( + document, opt_tag, opt_class, opt_el); +}; + + /** * Returns a static, array-like list of the elements with the provided * className. @@ -231,11 +272,9 @@ goog.dom.getElementByClass = function(className, opt_el) { var retVal = null; if (parent.getElementsByClassName) { retVal = parent.getElementsByClassName(className)[0]; - } else if (goog.dom.canUseQuerySelector_(parent)) { - retVal = parent.querySelector('.' + className); } else { - retVal = goog.dom.getElementsByTagNameAndClass_( - document, '*', className, opt_el)[0]; + retVal = + goog.dom.getElementByTagNameAndClass_(document, '*', className, opt_el); } return retVal || null; }; @@ -273,17 +312,23 @@ goog.dom.canUseQuerySelector_ = function(parent) { /** * Helper for {@code getElementsByTagNameAndClass}. * @param {!Document} doc The document to get the elements in. - * @param {?string=} opt_tag Element tag name. + * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name. * @param {?string=} opt_class Optional class name. * @param {(Document|Element)=} opt_el Optional element to look in. - * @return {!IArrayLike} Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). + * @return {!IArrayLike} Array-like list of elements (only a length property + * and numerical indices are guaranteed to exist). The members of the array + * are {!Element} if opt_tag is not a member of goog.dom.TagName or more + * specific types if it is (e.g. {!HTMLAnchorElement} for + * goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: * @private */ goog.dom.getElementsByTagNameAndClass_ = function( doc, opt_tag, opt_class, opt_el) { var parent = opt_el || doc; - var tagName = (opt_tag && opt_tag != '*') ? opt_tag.toUpperCase() : ''; + var tagName = + (opt_tag && opt_tag != '*') ? String(opt_tag).toUpperCase() : ''; if (goog.dom.canUseQuerySelector_(parent) && (tagName || opt_class)) { var query = tagName + (opt_class ? '.' + opt_class : ''); @@ -335,25 +380,81 @@ goog.dom.getElementsByTagNameAndClass_ = function( }; +/** + * Helper for goog.dom.getElementByTagNameAndClass. + * + * @param {!Document} doc The document to get the elements in. + * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name. + * @param {?string=} opt_class Optional class name. + * @param {(Document|Element)=} opt_el Optional element to look in. + * @return {?R} Reference to a DOM node. The return type is {?Element} if + * tagName is a string or a more specific type if it is a member of + * goog.dom.TagName (e.g. {?HTMLAnchorElement} for goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: + * @private + */ +goog.dom.getElementByTagNameAndClass_ = function( + doc, opt_tag, opt_class, opt_el) { + var parent = opt_el || doc; + var tag = (opt_tag && opt_tag != '*') ? String(opt_tag).toUpperCase() : ''; + if (goog.dom.canUseQuerySelector_(parent) && (tag || opt_class)) { + return parent.querySelector(tag + (opt_class ? '.' + opt_class : '')); + } + var elements = + goog.dom.getElementsByTagNameAndClass_(doc, opt_tag, opt_class, opt_el); + return elements[0] || null; +}; + + + /** * Alias for {@code getElementsByTagNameAndClass}. - * @param {?string=} opt_tag Element tag name. + * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name. * @param {?string=} opt_class Optional class name. * @param {Element=} opt_el Optional element to look in. - * @return {!IArrayLike} Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). + * @return {!IArrayLike} Array-like list of elements (only a length property + * and numerical indices are guaranteed to exist). The members of the array + * are {!Element} if opt_tag is not a member of goog.dom.TagName or more + * specific types if it is (e.g. {!HTMLAnchorElement} for + * goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: * @deprecated Use {@link goog.dom.getElementsByTagNameAndClass} instead. */ goog.dom.$$ = goog.dom.getElementsByTagNameAndClass; /** - * Sets multiple properties on a node. + * Sets multiple properties, and sometimes attributes, on an element. Note that + * properties are simply object properties on the element instance, while + * attributes are visible in the DOM. Many properties map to attributes with the + * same names, some with different names, and there are also unmappable cases. + * + * This method sets properties by default (which means that custom attributes + * are not supported). These are the exeptions (some of which is legacy): + * - "style": Even though this is an attribute name, it is translated to a + * property, "style.cssText". Note that this property sanitizes and formats + * its value, unlike the attribute. + * - "class": This is an attribute name, it is translated to the "className" + * property. + * - "for": This is an attribute name, it is translated to the "htmlFor" + * property. + * - Entries in {@see goog.dom.DIRECT_ATTRIBUTE_MAP_} are set as attributes, + * this is probably due to browser quirks. + * - "aria-*", "data-*": Always set as attributes, they have no property + * counterparts. + * * @param {Element} element DOM node to set properties on. * @param {Object} properties Hash of property:value pairs. + * Property values can be strings or goog.string.TypedString values (such as + * goog.html.SafeUrl). */ goog.dom.setProperties = function(element, properties) { goog.object.forEach(properties, function(val, key) { + if (val && val.implementsGoogStringTypedString) { + val = val.getTypedStringValue(); + } if (key == 'style') { element.style.cssText = val; } else if (key == 'class') { @@ -674,7 +775,7 @@ goog.dom.getWindow = function(opt_doc) { * @private */ goog.dom.getWindow_ = function(doc) { - return doc.parentWindow || doc.defaultView; + return /** @type {!Window} */ (doc.parentWindow || doc.defaultView); }; @@ -684,18 +785,26 @@ goog.dom.getWindow_ = function(doc) { * first node as childNodes. * * So: - * createDom('div', null, createDom('p'), createDom('p')); - * would return a div with two child paragraphs + * createDom(goog.dom.TagName.DIV, null, createDom(goog.dom.TagName.P), + * createDom(goog.dom.TagName.P)); would return a div with two child + * paragraphs * - * @param {string} tagName Tag to create. - * @param {(Object|Array|string)=} opt_attributes If object, then a map + * For passing properties, please see {@link goog.dom.setProperties} for more + * information. + * + * @param {string|!goog.dom.TagName} tagName Tag to create. + * @param {?Object|?Array|string=} opt_attributes If object, then a map * of name-value pairs for attributes. If a string, then this is the * className of the new element. If an array, the elements will be joined * together as the className of the new element. * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or * strings for text nodes. If one of the var_args is an array or NodeList, * its elements will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. + * @return {R} Reference to a DOM node. The return type is {!Element} if tagName + * is a string or a more specific type if it is a member of + * goog.dom.TagName (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: */ goog.dom.createDom = function(tagName, opt_attributes, var_args) { return goog.dom.createDom_(document, arguments); @@ -711,7 +820,7 @@ goog.dom.createDom = function(tagName, opt_attributes, var_args) { * @private */ goog.dom.createDom_ = function(doc, args) { - var tagName = args[0]; + var tagName = String(args[0]); var attributes = args[1]; // Internet Explorer is dumb: @@ -797,14 +906,19 @@ goog.dom.append_ = function(doc, parent, args, startIndex) { /** * Alias for {@code createDom}. - * @param {string} tagName Tag to create. - * @param {(string|Object)=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. + * @param {string|!goog.dom.TagName} tagName Tag to create. + * @param {?Object|?Array|string=} opt_attributes If object, then a map + * of name-value pairs for attributes. If a string, then this is the + * className of the new element. If an array, the elements will be joined + * together as the className of the new element. * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or * strings for text nodes. If one of the var_args is an array, its * children will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. + * @return {R} Reference to a DOM node. The return type is {!Element} if tagName + * is a string or a more specific type if it is a member of + * goog.dom.TagName (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: * @deprecated Use {@link goog.dom.createDom} instead. */ goog.dom.$dom = goog.dom.createDom; @@ -812,11 +926,31 @@ goog.dom.$dom = goog.dom.createDom; /** * Creates a new element. - * @param {string} name Tag name. - * @return {!Element} The new element. + * @param {string|!goog.dom.TagName} name Tag to create. + * @return {R} The new element. The return type is {!Element} if name is + * a string or a more specific type if it is a member of goog.dom.TagName + * (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: */ goog.dom.createElement = function(name) { - return document.createElement(name); + return goog.dom.createElement_(document, name); +}; + + +/** + * Creates a new element. + * @param {!Document} doc The document to create the element in. + * @param {string|!goog.dom.TagName} name Tag to create. + * @return {R} The new element. The return type is {!Element} if name is + * a string or a more specific type if it is a member of goog.dom.TagName + * (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A). + * @template T + * @template R := cond(isUnknown(T), 'Element', T) =: + * @private + */ +goog.dom.createElement_ = function(doc, name) { + return doc.createElement(String(name)); }; @@ -839,7 +973,7 @@ goog.dom.createTextNode = function(content) { * @return {!Element} The created table. */ goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) { - // TODO(user): Return HTMLTableElement, also in prototype function. + // TODO(mlourenco): Return HTMLTableElement, also in prototype function. // Callers need to be updated to e.g. not assign numbers to table.cellSpacing. return goog.dom.createTable_(document, rows, columns, !!opt_fillWithNbsp); }; @@ -856,13 +990,13 @@ goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) { * @private */ goog.dom.createTable_ = function(doc, rows, columns, fillWithNbsp) { - var table = /** @type {!HTMLTableElement} */ - (doc.createElement(goog.dom.TagName.TABLE)); - var tbody = table.appendChild(doc.createElement(goog.dom.TagName.TBODY)); + var table = goog.dom.createElement_(doc, goog.dom.TagName.TABLE); + var tbody = + table.appendChild(goog.dom.createElement_(doc, goog.dom.TagName.TBODY)); for (var i = 0; i < rows; i++) { - var tr = doc.createElement(goog.dom.TagName.TR); + var tr = goog.dom.createElement_(doc, goog.dom.TagName.TR); for (var j = 0; j < columns; j++) { - var td = doc.createElement(goog.dom.TagName.TD); + var td = goog.dom.createElement_(doc, goog.dom.TagName.TD); // IE <= 9 will create a text node if we set text content to the empty // string, so we avoid doing it unless necessary. This ensures that the // same DOM tree is returned on all browsers. @@ -916,7 +1050,7 @@ goog.dom.safeHtmlToNode = function(html) { * @private */ goog.dom.safeHtmlToNode_ = function(doc, html) { - var tempDiv = doc.createElement(goog.dom.TagName.DIV); + var tempDiv = goog.dom.createElement_(doc, goog.dom.TagName.DIV); if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { goog.dom.safe.setInnerHtml( tempDiv, goog.html.SafeHtml.concat(goog.html.SafeHtml.BR, html)); @@ -986,7 +1120,7 @@ goog.dom.isCss1CompatMode_ = function(doc) { * the behavior is inconsistent: * *
- *   var a = document.createElement(goog.dom.TagName.BR);
+ *   var a = goog.dom.createElement(goog.dom.TagName.BR);
  *   a.appendChild(document.createTextNode('foo'));
  *   a.appendChild(document.createTextNode('bar'));
  *   console.log(a.childNodes.length);  // 2
@@ -1006,31 +1140,31 @@ goog.dom.canHaveChildren = function(node) {
     return false;
   }
   switch (/** @type {!Element} */ (node).tagName) {
-    case goog.dom.TagName.APPLET:
-    case goog.dom.TagName.AREA:
-    case goog.dom.TagName.BASE:
-    case goog.dom.TagName.BR:
-    case goog.dom.TagName.COL:
-    case goog.dom.TagName.COMMAND:
-    case goog.dom.TagName.EMBED:
-    case goog.dom.TagName.FRAME:
-    case goog.dom.TagName.HR:
-    case goog.dom.TagName.IMG:
-    case goog.dom.TagName.INPUT:
-    case goog.dom.TagName.IFRAME:
-    case goog.dom.TagName.ISINDEX:
-    case goog.dom.TagName.KEYGEN:
-    case goog.dom.TagName.LINK:
-    case goog.dom.TagName.NOFRAMES:
-    case goog.dom.TagName.NOSCRIPT:
-    case goog.dom.TagName.META:
-    case goog.dom.TagName.OBJECT:
-    case goog.dom.TagName.PARAM:
-    case goog.dom.TagName.SCRIPT:
-    case goog.dom.TagName.SOURCE:
-    case goog.dom.TagName.STYLE:
-    case goog.dom.TagName.TRACK:
-    case goog.dom.TagName.WBR:
+    case String(goog.dom.TagName.APPLET):
+    case String(goog.dom.TagName.AREA):
+    case String(goog.dom.TagName.BASE):
+    case String(goog.dom.TagName.BR):
+    case String(goog.dom.TagName.COL):
+    case String(goog.dom.TagName.COMMAND):
+    case String(goog.dom.TagName.EMBED):
+    case String(goog.dom.TagName.FRAME):
+    case String(goog.dom.TagName.HR):
+    case String(goog.dom.TagName.IMG):
+    case String(goog.dom.TagName.INPUT):
+    case String(goog.dom.TagName.IFRAME):
+    case String(goog.dom.TagName.ISINDEX):
+    case String(goog.dom.TagName.KEYGEN):
+    case String(goog.dom.TagName.LINK):
+    case String(goog.dom.TagName.NOFRAMES):
+    case String(goog.dom.TagName.NOSCRIPT):
+    case String(goog.dom.TagName.META):
+    case String(goog.dom.TagName.OBJECT):
+    case String(goog.dom.TagName.PARAM):
+    case String(goog.dom.TagName.SCRIPT):
+    case String(goog.dom.TagName.SOURCE):
+    case String(goog.dom.TagName.STYLE):
+    case String(goog.dom.TagName.TRACK):
+    case String(goog.dom.TagName.WBR):
       return false;
   }
   return true;
@@ -1363,8 +1497,8 @@ goog.dom.getParentElement = function(element) {
 
 /**
  * Whether a node contains another node.
- * @param {?Node} parent The node that should contain the other node.
- * @param {?Node} descendant The node to test presence of.
+ * @param {?Node|undefined} parent The node that should contain the other node.
+ * @param {?Node|undefined} descendant The node to test presence of.
  * @return {boolean} Whether the parent node contains the descendent node.
  */
 goog.dom.contains = function(parent, descendant) {
@@ -1623,7 +1757,7 @@ goog.dom.setTextContent = function(node, text) {
   if ('textContent' in node) {
     node.textContent = text;
   } else if (node.nodeType == goog.dom.NodeType.TEXT) {
-    node.data = text;
+    /** @type {!Text} */ (node).data = String(text);
   } else if (
       node.firstChild && node.firstChild.nodeType == goog.dom.NodeType.TEXT) {
     // If the first child is a text node we just change its data and remove the
@@ -1631,7 +1765,7 @@ goog.dom.setTextContent = function(node, text) {
     while (node.lastChild != node.firstChild) {
       node.removeChild(node.lastChild);
     }
-    node.firstChild.data = text;
+    /** @type {!Text} */ (node.firstChild).data = String(text);
   } else {
     goog.dom.removeChildren(node);
     var doc = goog.dom.getOwnerDocument(node);
@@ -1655,7 +1789,7 @@ goog.dom.getOuterHtml = function(element) {
     return element.outerHTML;
   } else {
     var doc = goog.dom.getOwnerDocument(element);
-    var div = doc.createElement(goog.dom.TagName.DIV);
+    var div = goog.dom.createElement_(doc, goog.dom.TagName.DIV);
     div.appendChild(element.cloneNode(true));
     return div.innerHTML;
   }
@@ -1828,11 +1962,14 @@ goog.dom.isFocusable = function(element) {
  * @private
  */
 goog.dom.hasSpecifiedTabIndex_ = function(element) {
-  // IE returns 0 for an unset tabIndex, so we must use getAttributeNode(),
-  // which returns an object with a 'specified' property if tabIndex is
-  // specified.  This works on other browsers, too.
-  var attrNode = element.getAttributeNode('tabindex');  // Must be lowercase!
-  return goog.isDefAndNotNull(attrNode) && attrNode.specified;
+  // IE8 and below don't support hasAttribute(), instead check whether the
+  // 'tabindex' attributeNode is specified. Otherwise check hasAttribute().
+  if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')) {
+    var attrNode = element.getAttributeNode('tabindex');  // Must be lowercase!
+    return goog.isDefAndNotNull(attrNode) && attrNode.specified;
+  } else {
+    return element.hasAttribute('tabindex');
+  }
 };
 
 
@@ -2085,21 +2222,25 @@ goog.dom.isNodeList = function(val) {
  * tag name and/or class name. If the passed element matches the specified
  * criteria, the element itself is returned.
  * @param {Node} element The DOM node to start with.
- * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or
+ * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or
  *     null/undefined to match only based on class name).
  * @param {?string=} opt_class The class name to match (or null/undefined to
  *     match only based on tag name).
  * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
  *     dom.
- * @return {Element} The first ancestor that matches the passed criteria, or
- *     null if no match is found.
+ * @return {?R} The first ancestor that matches the passed criteria, or
+ *     null if no match is found. The return type is {?Element} if opt_tag is
+ *     not a member of goog.dom.TagName or a more specific type if it is (e.g.
+ *     {?HTMLAnchorElement} for goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  */
 goog.dom.getAncestorByTagNameAndClass = function(
     element, opt_tag, opt_class, opt_maxSearchSteps) {
   if (!opt_tag && !opt_class) {
     return null;
   }
-  var tagName = opt_tag ? opt_tag.toUpperCase() : null;
+  var tagName = opt_tag ? String(opt_tag).toUpperCase() : null;
   return /** @type {Element} */ (goog.dom.getAncestor(element, function(node) {
     return (!tagName || node.nodeName == tagName) &&
         (!opt_class ||
@@ -2142,7 +2283,7 @@ goog.dom.getAncestorByClass = function(element, className, opt_maxSearchSteps) {
  */
 goog.dom.getAncestor = function(
     element, matcher, opt_includeNode, opt_maxSearchSteps) {
-  if (!opt_includeNode) {
+  if (element && !opt_includeNode) {
     element = element.parentNode;
   }
   var steps = 0;
@@ -2201,9 +2342,11 @@ goog.dom.getPixelRatio = function() {
   if (goog.isDef(win.devicePixelRatio)) {
     return win.devicePixelRatio;
   } else if (win.matchMedia) {
-    return goog.dom.matchesPixelRatio_(.75) ||
-        goog.dom.matchesPixelRatio_(1.5) || goog.dom.matchesPixelRatio_(2) ||
-        goog.dom.matchesPixelRatio_(3) || 1;
+    // Should be for IE10 and FF6-17 (this basically clamps to lower)
+    // Note that the order of these statements is important
+    return goog.dom.matchesPixelRatio_(3) || goog.dom.matchesPixelRatio_(2) ||
+           goog.dom.matchesPixelRatio_(1.5) || goog.dom.matchesPixelRatio_(1) ||
+           .75;
   }
   return 1;
 };
@@ -2218,14 +2361,35 @@ goog.dom.getPixelRatio = function() {
  */
 goog.dom.matchesPixelRatio_ = function(pixelRatio) {
   var win = goog.dom.getWindow();
+  /**
+   * Due to the 1:96 fixed ratio of CSS in to CSS px, 1dppx is equivalent to
+   * 96dpi.
+   * @const {number}
+   */
+  var dpiPerDppx = 96;
   var query =
-      ('(-webkit-min-device-pixel-ratio: ' + pixelRatio + '),' +
-       '(min--moz-device-pixel-ratio: ' + pixelRatio + '),' +
-       '(min-resolution: ' + pixelRatio + 'dppx)');
+      // FF16-17
+      '(min-resolution: ' + pixelRatio + 'dppx),' +
+      // FF6-15
+      '(min--moz-device-pixel-ratio: ' + pixelRatio + '),' +
+      // IE10 (this works for the two browsers above too but I don't want to
+      // trust the 1:96 fixed ratio magic)
+      '(min-resolution: ' + (pixelRatio * dpiPerDppx) + 'dpi)';
   return win.matchMedia(query).matches ? pixelRatio : 0;
 };
 
 
+/**
+ * Gets '2d' context of a canvas. Shortcut for canvas.getContext('2d') with a
+ * type information.
+ * @param {!HTMLCanvasElement} canvas
+ * @return {!CanvasRenderingContext2D}
+ */
+goog.dom.getCanvasContext2D = function(canvas) {
+  return /** @type {!CanvasRenderingContext2D} */ (canvas.getContext('2d'));
+};
+
+
 
 /**
  * Create an instance of a DOM helper with a new document object.
@@ -2303,6 +2467,25 @@ goog.dom.DomHelper.prototype.getRequiredElement = function(id) {
 goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement;
 
 
+/**
+ * Gets elements by tag name.
+ * @param {!goog.dom.TagName} tagName
+ * @param {(!Document|!Element)=} opt_parent Parent element or document where to
+ *     look for elements. Defaults to document of this DomHelper.
+ * @return {!NodeList} List of elements. The members of the list are
+ *     {!Element} if tagName is not a member of goog.dom.TagName or more
+ *     specific types if it is (e.g. {!HTMLAnchorElement} for
+ *     goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
+ */
+goog.dom.DomHelper.prototype.getElementsByTagName =
+    function(tagName, opt_parent) {
+  var parent = opt_parent || this.document_;
+  return parent.getElementsByTagName(String(tagName));
+};
+
+
 /**
  * Looks up elements by both tag and class name, using browser native functions
  * ({@code querySelectorAll}, {@code getElementsByTagName} or
@@ -2311,11 +2494,17 @@ goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement;
  *
  * @see goog.dom.query
  *
- * @param {?string=} opt_tag Element tag name or * for all tags.
+ * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name or * for all
+ *     tags.
  * @param {?string=} opt_class Optional class name.
  * @param {(Document|Element)=} opt_el Optional element to look in.
- * @return {!IArrayLike} Array-like list of elements (only a length
- *     property and numerical indices are guaranteed to exist).
+ * @return {!IArrayLike} Array-like list of elements (only a length property
+ *     and numerical indices are guaranteed to exist). The members of the array
+ *     are {!Element} if opt_tag is not a member of goog.dom.TagName or more
+ *     specific types if it is (e.g. {!HTMLAnchorElement} for
+ *     goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  */
 goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(
     opt_tag, opt_class, opt_el) {
@@ -2324,6 +2513,25 @@ goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(
 };
 
 
+/**
+ * Gets the first element matching the tag and the class.
+ *
+ * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name.
+ * @param {?string=} opt_class Optional class name.
+ * @param {(Document|Element)=} opt_el Optional element to look in.
+ * @return {?R} Reference to a DOM node. The return type is {?Element} if
+ *     tagName is a string or a more specific type if it is a member of
+ *     goog.dom.TagName (e.g. {?HTMLAnchorElement} for goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
+ */
+goog.dom.DomHelper.prototype.getElementByTagNameAndClass = function(
+    opt_tag, opt_class, opt_el) {
+  return goog.dom.getElementByTagNameAndClass_(
+      this.document_, opt_tag, opt_class, opt_el);
+};
+
+
 /**
  * Returns an array of all the elements with the provided className.
  * @see {goog.dom.query}
@@ -2372,11 +2580,16 @@ goog.dom.DomHelper.prototype.getRequiredElementByClass = function(
  * @deprecated Use DomHelper getElementsByTagNameAndClass.
  * @see goog.dom.query
  *
- * @param {?string=} opt_tag Element tag name.
+ * @param {(string|?goog.dom.TagName)=} opt_tag Element tag name.
  * @param {?string=} opt_class Optional class name.
  * @param {Element=} opt_el Optional element to look in.
- * @return {!IArrayLike} Array-like list of elements (only a length
- *     property and numerical indices are guaranteed to exist).
+ * @return {!IArrayLike} Array-like list of elements (only a length property
+ *     and numerical indices are guaranteed to exist). The members of the array
+ *     are {!Element} if opt_tag is a string or more specific types if it is
+ *     a member of goog.dom.TagName (e.g. {!HTMLAnchorElement} for
+ *     goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  */
 goog.dom.DomHelper.prototype.$$ =
     goog.dom.DomHelper.prototype.getElementsByTagNameAndClass;
@@ -2426,23 +2639,29 @@ goog.dom.Appendable;
  * first node as childNodes.
  *
  * So:
- * createDom('div', null, createDom('p'), createDom('p'));
- * would return a div with two child paragraphs
+ * createDom(goog.dom.TagName.DIV, null, createDom(goog.dom.TagName.P),
+ * createDom(goog.dom.TagName.P)); would return a div with two child
+ * paragraphs
  *
  * An easy way to move all child nodes of an existing element to a new parent
  * element is:
- * createDom('div', null, oldElement.childNodes);
+ * createDom(goog.dom.TagName.DIV, null, oldElement.childNodes);
  * which will remove all child nodes from the old element and add them as
  * child nodes of the new DIV.
  *
- * @param {string} tagName Tag to create.
- * @param {Object|string=} opt_attributes If object, then a map of name-value
- *     pairs for attributes. If a string, then this is the className of the new
- *     element.
+ * @param {string|!goog.dom.TagName} tagName Tag to create.
+ * @param {?Object|?Array|string=} opt_attributes If object, then a map
+ *     of name-value pairs for attributes. If a string, then this is the
+ *     className of the new element. If an array, the elements will be joined
+ *     together as the className of the new element.
  * @param {...goog.dom.Appendable} var_args Further DOM nodes or
  *     strings for text nodes. If one of the var_args is an array or
  *     NodeList, its elements will be added as childNodes instead.
- * @return {!Element} Reference to a DOM node.
+ * @return {R} Reference to a DOM node. The return type is {!Element} if tagName
+ *     is a string or a more specific type if it is a member of
+ *     goog.dom.TagName (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  */
 goog.dom.DomHelper.prototype.createDom = function(
     tagName, opt_attributes, var_args) {
@@ -2452,14 +2671,19 @@ goog.dom.DomHelper.prototype.createDom = function(
 
 /**
  * Alias for {@code createDom}.
- * @param {string} tagName Tag to create.
- * @param {(Object|string)=} opt_attributes If object, then a map of name-value
- *     pairs for attributes. If a string, then this is the className of the new
- *     element.
+ * @param {string|!goog.dom.TagName} tagName Tag to create.
+ * @param {?Object|?Array|string=} opt_attributes If object, then a map
+ *     of name-value pairs for attributes. If a string, then this is the
+ *     className of the new element. If an array, the elements will be joined
+ *     together as the className of the new element.
  * @param {...goog.dom.Appendable} var_args Further DOM nodes or strings for
  *     text nodes.  If one of the var_args is an array, its children will be
  *     added as childNodes instead.
- * @return {!Element} Reference to a DOM node.
+ * @return {R} Reference to a DOM node. The return type is {!Element} if tagName
+ *     is a string or a more specific type if it is a member of
+ *     goog.dom.TagName (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  * @deprecated Use {@link goog.dom.DomHelper.prototype.createDom} instead.
  */
 goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom;
@@ -2467,11 +2691,15 @@ goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom;
 
 /**
  * Creates a new element.
- * @param {string} name Tag name.
- * @return {!Element} The new element.
+ * @param {string|!goog.dom.TagName} name Tag to create.
+ * @return {R} The new element. The return type is {!Element} if name is
+ *     a string or a more specific type if it is a member of goog.dom.TagName
+ *     (e.g. {!HTMLAnchorElement} for goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  */
 goog.dom.DomHelper.prototype.createElement = function(name) {
-  return this.document_.createElement(name);
+  return goog.dom.createElement_(this.document_, name);
 };
 
 
@@ -2948,14 +3176,18 @@ goog.dom.DomHelper.prototype.isNodeList = goog.dom.isNodeList;
  * tag name and/or class name. If the passed element matches the specified
  * criteria, the element itself is returned.
  * @param {Node} element The DOM node to start with.
- * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or
+ * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or
  *     null/undefined to match only based on class name).
  * @param {?string=} opt_class The class name to match (or null/undefined to
  *     match only based on tag name).
  * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
  *     dom.
- * @return {Element} The first ancestor that matches the passed criteria, or
- *     null if no match is found.
+ * @return {?R} The first ancestor that matches the passed criteria, or
+ *     null if no match is found. The return type is {?Element} if opt_tag is
+ *     not a member of goog.dom.TagName or a more specific type if it is (e.g.
+ *     {?HTMLAnchorElement} for goog.dom.TagName.A).
+ * @template T
+ * @template R := cond(isUnknown(T), 'Element', T) =:
  */
 goog.dom.DomHelper.prototype.getAncestorByTagNameAndClass =
     goog.dom.getAncestorByTagNameAndClass;
@@ -2990,3 +3222,12 @@ goog.dom.DomHelper.prototype.getAncestorByClass = goog.dom.getAncestorByClass;
  *     no match.
  */
 goog.dom.DomHelper.prototype.getAncestor = goog.dom.getAncestor;
+
+
+/**
+ * Gets '2d' context of a canvas. Shortcut for canvas.getContext('2d') with a
+ * type information.
+ * @param {!HTMLCanvasElement} canvas
+ * @return {!CanvasRenderingContext2D}
+ */
+goog.dom.DomHelper.prototype.getCanvasContext2D = goog.dom.getCanvasContext2D;
-- 
cgit v1.2.3