Use material tooltips

Tooltips will be used in the future for other features, and this allows
existing plain tooltips to be shown as soon as the mouse enters the
element, without the long delay inherent to standard tooltips.

Bug: twpowertools:45
Change-Id: Ifa7bf1ee8db8da7afaf36b9d19448f5a0cdd4ebc
diff --git a/src/common/tooltip.js b/src/common/tooltip.js
new file mode 100644
index 0000000..6657c58
--- /dev/null
+++ b/src/common/tooltip.js
@@ -0,0 +1,62 @@
+import {MDCTooltip} from '@material/tooltip';
+
+const probCleanOrphanTooltips = 0.07;
+
+const currentTooltips = new Set();
+
+// For each tooltip, if the element which is being described by it no longer
+// exists, delete it.
+function cleanOrphanTooltips() {
+  return new Promise((res, rej) => {
+    for (const tooltip of currentTooltips) {
+      if (document.querySelector('[aria-describedby="' + tooltip.id + '"]') ===
+          null) {
+        currentTooltips.delete(tooltip);
+        tooltip.remove();
+      }
+    }
+    res();
+  });
+}
+
+export function createPlainTooltip(srcElement, label, initTooltip = true) {
+  if (srcElement.hasAttribute('aria-describedby')) {
+    let tooltip =
+        document.getElementById(srcElement.getAttribute('aria-describedby'));
+    if (tooltip !== null) tooltip.remove();
+  }
+
+  let tooltip = document.createElement('div');
+  let tooltipId;
+  do {
+    // Idea from: https://stackoverflow.com/a/44078785
+    let randomId =
+        Date.now().toString(36) + Math.random().toString(36).substring(2);
+    tooltipId = 'TWPT_tooltip_' + randomId;
+  } while (document.getElementById(tooltipId) !== null);
+  tooltip.id = tooltipId;
+  tooltip.classList.add('mdc-tooltip');
+  tooltip.setAttribute('role', 'tooltip');
+  tooltip.setAttribute('aria-hidden', 'true');
+
+  let surface = document.createElement('div');
+  surface.classList.add(
+      'mdc-tooltip__surface', 'mdc-tooltip__surface-animation');
+  surface.textContent = label;
+
+  tooltip.append(surface);
+
+  // In the Community Console we inject the tooltip into
+  // #default-acx-overlay-container, and in TW directly into the body.
+  var tooltipParent =
+      document.getElementById('default-acx-overlay-container') ?? document.body;
+  tooltipParent.append(tooltip);
+  currentTooltips.add(tooltip);
+
+  srcElement.setAttribute('aria-describedby', tooltipId);
+
+  if (Math.random() < probCleanOrphanTooltips) cleanOrphanTooltips();
+
+  if (initTooltip) return new MDCTooltip(tooltip);
+  return tooltip;
+}