0db69910b2561b37d888bdff69895117eea55175 chmalee Thu Apr 23 12:00:09 2026 -0700 Make file names in hubSpace links to view/download the files. Add a copy icon next to each file that copies the url for easy linking to hub.txts, refs Max/Baihe email diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js index d08d91f1d34..d7fae2f2bcc 100644 --- src/hg/js/hgMyData.js +++ src/hg/js/hgMyData.js @@ -1585,31 +1585,40 @@ render: DataTable.render.select(), }, { orderable: false, targets: 1, data: "action", title: "", render: function(data, type, row) { if (type === "display") { return dataTablePrintAction(row); } return ''; } }, { targets: 2, render: function(data, type, row, meta) { - return decodeURIComponent(data); + let decodedName = decodeURIComponent(data); + if (type !== "display" || row.fileType === "dir") { + return decodedName; + } + if (typeof uiState.userUrl === "undefined" || uiState.userUrl.length === 0) { + return decodedName; + } + let fileUrl = uiState.userUrl + cgiEncode(row.fullPath); + let copyIcon = ''; + return '' + decodedName + '' + copyIcon; } }, { targets: 3, render: function(data, type, row, meta) { if (type === "display") { return dataTablePrintSize(data, type, row, meta); } return data; } }, { targets: 5, render: function(data, type, row) { if (type === "display") { @@ -1717,30 +1726,56 @@ }); } else { table.buttons(".uploadButton").disable(); } table.on("select", function(e, dt, type, indexes) { indexes.forEach(function(i) { doRowSelect(e.type, dt, i); }); }); table.on("deselect", function(e, dt, type, indexes) { indexes.forEach(function(i) { doRowSelect(e.type, dt, i); }); }); table.on("click", function(e) { + let copyIcon = e.target.closest ? e.target.closest(".copyLinkIcon") : null; + if (copyIcon) { + e.stopPropagation(); + e.preventDefault(); + let url = copyIcon.getAttribute("data-url"); + navigator.clipboard.writeText(url).then(function() { + let feedback = document.createElement("span"); + feedback.textContent = "copied"; + feedback.style.marginLeft = "6px"; + feedback.style.fontSize = "0.85em"; + feedback.style.color = "#080"; + copyIcon.parentNode.replaceChild(feedback, copyIcon); + setTimeout(function() { + if (feedback.parentNode) { + feedback.parentNode.replaceChild(copyIcon, feedback); + } + }, 1500); + }, function() { + alert("Failed to copy URL: " + url); + }); + return; + } + if (e.target.closest && e.target.closest(".fileLink")) { + e.stopPropagation(); + return; + } if (e.target.className !== "dt-select-checkbox") { e.stopPropagation(); // we've clicked somewhere not on the checkbox itself, we need to: // 1. open the directory if the clicked row is a directory // 2. select the file if the clicked row is a regular file let row = table.row(e.target); let data = row.data(); if (data.children && data.children.length > 0) { dataTableShowDir(table, data.fileName, data.fullPath); dataTableCustomOrder(table, {"fullPath": data.fullPath}); table.draw(); } else { if (row.selected()) { row.deselect(); doRowSelect("deselect", table, row.index());