9fb48fcf916f66ad45f316969a25599c82fe385e
max
  Tue Jun 14 07:34:25 2022 -0700
adding copy to clipboard feature to hgSession.c. refs #29586

diff --git src/hg/js/utils.js src/hg/js/utils.js
index e221c4d..685c674 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -1,24 +1,48 @@
 // Utility JavaScript
 
 // "use strict";
 
 // Don't complain about line break before '||' etc:
 /* jshint -W014 */
 
 var debug = false;
 
+function copyToClipboard(ev) {
+    /* copy a piece of text to clipboard. event.target is some DIV or SVG that is an icon. 
+     * The attribute data-target of this element is the ID of the element that contains the text to copy. 
+     * see C function printCopyToClipboardButton(iconId, targetId);
+     * */
+     
+    var targetId = ev.target.getAttribute("data-target");
+    var textEl = document.getElementById(targetId);
+    var text = textEl.innerText;
+
+    var textArea = document.createElement("textarea");
+    textArea.value = text;
+    // Avoid scrolling to bottom
+    textArea.style.top = "0";
+    textArea.style.left = "0";
+    textArea.style.position = "fixed";
+    document.body.appendChild(textArea);
+    textArea.focus();
+    textArea.select();
+    document.execCommand('copy');
+    document.body.removeChild(textArea);
+    alert("Copied text "+text+" to clipboard.");
+}
+
 function cfgPageOnVisChange(ev) {
     /* configuration page event listener when user changes visibility in dropdown */
     if (ev.target.value === 'hide')
         ev.target.classList.replace("normalText", "hiddenText");
     else
         ev.target.classList.replace("hiddenText", "normalText");
 }
 
 function cfgPageAddListeners() {
     /* add event listener to dropdowns */
     var els = document.querySelectorAll(".trackVis");
     for (var i=0; i < els.length; i++) {
         var el = els[i];
         el.addEventListener("change", cfgPageOnVisChange );
     }