diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html
index 23001f92c..08f0b9faa 100644
--- a/src/webui/www/private/index.html
+++ b/src/webui/www/private/index.html
@@ -31,7 +31,7 @@
-
+
diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js
index d0b13f1c1..91d6f4695 100644
--- a/src/webui/www/private/scripts/client.js
+++ b/src/webui/www/private/scripts/client.js
@@ -1785,26 +1785,29 @@ window.addEventListener("DOMContentLoaded", (event) => {
}
});
- new ClipboardJS(".copyToClipboard", {
- text: (trigger) => {
- switch (trigger.id) {
- case "copyName":
- return copyNameFN();
- case "copyInfohash1":
- return copyInfohashFN(1);
- case "copyInfohash2":
- return copyInfohashFN(2);
- case "copyMagnetLink":
- return copyMagnetLinkFN();
- case "copyID":
- return copyIdFN();
- case "copyComment":
- return copyCommentFN();
- default:
- return "";
- }
+ for (const element of document.getElementsByClassName("copyToClipboard")) {
+ const setupClickEvent = (textFunc) => element.addEventListener("click", async (event) => await clipboardCopy(textFunc()));
+ switch (element.id) {
+ case "copyName":
+ setupClickEvent(copyNameFN);
+ break;
+ case "copyInfohash1":
+ setupClickEvent(() => copyInfohashFN(1));
+ break;
+ case "copyInfohash2":
+ setupClickEvent(() => copyInfohashFN(2));
+ break;
+ case "copyMagnetLink":
+ setupClickEvent(copyMagnetLinkFN);
+ break;
+ case "copyID":
+ setupClickEvent(copyIdFN);
+ break;
+ case "copyComment":
+ setupClickEvent(copyCommentFN);
+ break;
}
- });
+ }
addEventListener("visibilitychange", (event) => {
if (document.hidden)
diff --git a/src/webui/www/private/scripts/lib/clipboard-copy.js b/src/webui/www/private/scripts/lib/clipboard-copy.js
new file mode 100644
index 000000000..bef3217f0
--- /dev/null
+++ b/src/webui/www/private/scripts/lib/clipboard-copy.js
@@ -0,0 +1,63 @@
+/*! clipboard-copy. MIT License. Feross Aboukhadijeh */
+/* global DOMException */
+
+//module.exports = clipboardCopy
+
+function makeError () {
+ return new DOMException('The request is not allowed', 'NotAllowedError')
+}
+
+async function copyClipboardApi (text) {
+ // Use the Async Clipboard API when available. Requires a secure browsing
+ // context (i.e. HTTPS)
+ if (!navigator.clipboard) {
+ throw makeError()
+ }
+ return navigator.clipboard.writeText(text)
+}
+
+async function copyExecCommand (text) {
+ // Put the text to copy into a
+ const span = document.createElement('span')
+ span.textContent = text
+
+ // Preserve consecutive spaces and newlines
+ span.style.whiteSpace = 'pre'
+ span.style.webkitUserSelect = 'auto'
+ span.style.userSelect = 'all'
+
+ // Add the to the page
+ document.body.appendChild(span)
+
+ // Make a selection object representing the range of text selected by the user
+ const selection = window.getSelection()
+ const range = window.document.createRange()
+ selection.removeAllRanges()
+ range.selectNode(span)
+ selection.addRange(range)
+
+ // Copy text to the clipboard
+ let success = false
+ try {
+ success = window.document.execCommand('copy')
+ } finally {
+ // Cleanup
+ selection.removeAllRanges()
+ window.document.body.removeChild(span)
+ }
+
+ if (!success) throw makeError()
+}
+
+async function clipboardCopy (text) {
+ try {
+ await copyClipboardApi(text)
+ } catch (err) {
+ // ...Otherwise, use document.execCommand() fallback
+ try {
+ await copyExecCommand(text)
+ } catch (err2) {
+ throw (err2 || err || makeError())
+ }
+ }
+}
diff --git a/src/webui/www/private/scripts/lib/clipboard.min.js b/src/webui/www/private/scripts/lib/clipboard.min.js
deleted file mode 100644
index 1103f811e..000000000
--- a/src/webui/www/private/scripts/lib/clipboard.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * clipboard.js v2.0.11
- * https://clipboardjs.com/
- *
- * Licensed MIT © Zeno Rocha
- */
-!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1 {
}
});
- new ClipboardJS("#CopyPeerInfo", {
- text: (trigger) => {
- return torrentPeersTable.selectedRowsIds().join("\n");
- }
+ document.getElementById("CopyPeerInfo").addEventListener("click", async (event) => {
+ const text = torrentPeersTable.selectedRowsIds().join("\n");
+ await clipboardCopy(text);
});
torrentPeersTable.setup("torrentPeersTableDiv", "torrentPeersTableFixedHeaderDiv", torrentPeersContextMenu, true);
diff --git a/src/webui/www/private/scripts/prop-trackers.js b/src/webui/www/private/scripts/prop-trackers.js
index 5261a7db2..7214895b4 100644
--- a/src/webui/www/private/scripts/prop-trackers.js
+++ b/src/webui/www/private/scripts/prop-trackers.js
@@ -248,10 +248,9 @@ window.qBittorrent.PropTrackers ??= (() => {
torrentTrackersTable.clear();
};
- new ClipboardJS("#CopyTrackerUrl", {
- text: (trigger) => {
- return torrentTrackersTable.selectedRowsIds().join("\n");
- }
+ document.getElementById("CopyTrackerUrl").addEventListener("click", async (event) => {
+ const text = torrentTrackersTable.selectedRowsIds().join("\n");
+ await clipboardCopy(text);
});
torrentTrackersTable.setup("torrentTrackersTableDiv", "torrentTrackersTableFixedHeaderDiv", torrentTrackersContextMenu, true);
diff --git a/src/webui/www/private/scripts/prop-webseeds.js b/src/webui/www/private/scripts/prop-webseeds.js
index 737642f69..3b756cfb5 100644
--- a/src/webui/www/private/scripts/prop-webseeds.js
+++ b/src/webui/www/private/scripts/prop-webseeds.js
@@ -219,10 +219,9 @@ window.qBittorrent.PropWebseeds ??= (() => {
torrentWebseedsTable.clear();
};
- new ClipboardJS("#CopyWebseedUrl", {
- text: (trigger) => {
- return torrentWebseedsTable.selectedRowsIds().join("\n");
- }
+ document.getElementById("CopyWebseedUrl").addEventListener("click", async (event) => {
+ const text = torrentWebseedsTable.selectedRowsIds().join("\n");
+ await clipboardCopy(text);
});
torrentWebseedsTable.setup("torrentWebseedsTableDiv", "torrentWebseedsTableFixedHeaderDiv", torrentWebseedsContextMenu, true);
diff --git a/src/webui/www/private/scripts/search.js b/src/webui/www/private/scripts/search.js
index b4b7e23db..ce3edf6cd 100644
--- a/src/webui/www/private/scripts/search.js
+++ b/src/webui/www/private/scripts/search.js
@@ -866,20 +866,20 @@ window.qBittorrent.Search ??= (() => {
state.loadResultsTimer = loadSearchResultsData.delay(500, this, searchId);
};
- new ClipboardJS(".copySearchDataToClipboard", {
- text: (trigger) => {
- switch (trigger.id) {
- case "copySearchTorrentName":
- return copySearchTorrentName();
- case "copySearchTorrentDownloadLink":
- return copySearchTorrentDownloadLink();
- case "copySearchTorrentDescriptionUrl":
- return copySearchTorrentDescriptionUrl();
- default:
- return "";
- }
+ for (const element of document.getElementsByClassName("copySearchDataToClipboard")) {
+ const setupClickEvent = (textFunc) => element.addEventListener("click", async (event) => await clipboardCopy(textFunc()));
+ switch (element.id) {
+ case "copySearchTorrentName":
+ setupClickEvent(copySearchTorrentName);
+ break;
+ case "copySearchTorrentDownloadLink":
+ setupClickEvent(copySearchTorrentDownloadLink);
+ break;
+ case "copySearchTorrentDescriptionUrl":
+ setupClickEvent(copySearchTorrentDescriptionUrl);
+ break;
}
- });
+ }
return exports();
})();
diff --git a/src/webui/www/private/views/log.html b/src/webui/www/private/views/log.html
index b7944b784..a1fc55472 100644
--- a/src/webui/www/private/views/log.html
+++ b/src/webui/www/private/views/log.html
@@ -144,7 +144,7 @@
@@ -418,15 +418,11 @@
});
};
- new ClipboardJS(".copyLogDataToClipboard", {
- text: () => {
- const msg = [];
- tableInfo[currentSelectedTab].instance.selectedRowsIds().forEach((rowId) => {
- msg.push(tableInfo[currentSelectedTab].instance.getRow(rowId).full_data[(currentSelectedTab === "main") ? "message" : "ip"]);
- });
-
- return msg.join("\n");
- }
+ document.getElementById("copyLogDataToClipboard").addEventListener("click", async (event) => {
+ const instance = tableInfo[currentSelectedTab].instance;
+ const type = (currentSelectedTab === "main") ? "message" : "ip";
+ const msg = instance.selectedRowsIds().map((rowId) => instance.getRow(rowId).full_data[type]);
+ await clipboardCopy(msg.join("\n"));
});
return exports();
diff --git a/src/webui/www/private/views/rss.html b/src/webui/www/private/views/rss.html
index 287e9741a..cd264b130 100644
--- a/src/webui/www/private/views/rss.html
+++ b/src/webui/www/private/views/rss.html
@@ -277,17 +277,16 @@
}
});
- new ClipboardJS("#CopyFeedURL", {
- text: () => {
- let joined = "";
- for (const rowID of rssFeedTable.selectedRows) {
- const row = rssFeedTable.getRow(rowID);
- if (row.full_data.dataUid !== "")
- joined += `${row.full_data.dataUrl}\n`;
- }
- return joined.slice(0, -1);
+ document.getElementById("CopyFeedURL").addEventListener("click", async (event) => {
+ let joined = "";
+ for (const rowID of rssFeedTable.selectedRows) {
+ const row = rssFeedTable.getRow(rowID);
+ if (row.full_data.dataUid !== "")
+ joined += `${row.full_data.dataUrl}\n`;
}
+ await clipboardCopy(joined.slice(0, -1));
});
+
rssFeedTable.setup("rssFeedTableDiv", "rssFeedFixedHeaderDiv", rssFeedContextMenu);
const rssArticleContextMenu = new window.qBittorrent.ContextMenu.RssArticleContextMenu({
diff --git a/src/webui/www/webui.qrc b/src/webui/www/webui.qrc
index d2ddbe9e6..864df1e6a 100644
--- a/src/webui/www/webui.qrc
+++ b/src/webui/www/webui.qrc
@@ -400,7 +400,7 @@
private/scripts/dynamicTable.js
private/scripts/file-tree.js
private/scripts/filesystem.js
- private/scripts/lib/clipboard.min.js
+ private/scripts/lib/clipboard-copy.js
private/scripts/lib/mocha.min.js
private/scripts/lib/MooTools-Core-1.6.0-compat-compressed.js
private/scripts/lib/MooTools-More-1.6.0-compat-compressed.js