mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-06-28 01:16:30 -04:00
WebUI: switch to lightweight clipboard library
The new library [1] will opt to the modern Clipboard API [2] when it is available. It will fallback to the old method otherwise. The new library is also smaller and without any bloat. Note that the line `module.exports` is required to be removed/commented out. This is the only patch required. [1] https://github.com/feross/clipboard-copy [2] https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API PR #22792.
This commit is contained in:
parent
4b07597d54
commit
96f0eebc4e
11 changed files with 123 additions and 72 deletions
|
@ -31,7 +31,7 @@
|
||||||
<script defer src="scripts/localpreferences.js?v=${CACHEID}"></script>
|
<script defer src="scripts/localpreferences.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/color-scheme.js?v=${CACHEID}"></script>
|
<script defer src="scripts/color-scheme.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/mocha-init.js?locale=${LANG}&v=${CACHEID}"></script>
|
<script defer src="scripts/mocha-init.js?locale=${LANG}&v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/lib/clipboard.min.js"></script>
|
<script defer src="scripts/lib/clipboard-copy.js"></script>
|
||||||
<script defer src="scripts/filesystem.js?v=${CACHEID}"></script>
|
<script defer src="scripts/filesystem.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/misc.js?locale=${LANG}&v=${CACHEID}"></script>
|
<script defer src="scripts/misc.js?locale=${LANG}&v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/progressbar.js?v=${CACHEID}"></script>
|
<script defer src="scripts/progressbar.js?v=${CACHEID}"></script>
|
||||||
|
|
|
@ -1785,26 +1785,29 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new ClipboardJS(".copyToClipboard", {
|
for (const element of document.getElementsByClassName("copyToClipboard")) {
|
||||||
text: (trigger) => {
|
const setupClickEvent = (textFunc) => element.addEventListener("click", async (event) => await clipboardCopy(textFunc()));
|
||||||
switch (trigger.id) {
|
switch (element.id) {
|
||||||
case "copyName":
|
case "copyName":
|
||||||
return copyNameFN();
|
setupClickEvent(copyNameFN);
|
||||||
case "copyInfohash1":
|
break;
|
||||||
return copyInfohashFN(1);
|
case "copyInfohash1":
|
||||||
case "copyInfohash2":
|
setupClickEvent(() => copyInfohashFN(1));
|
||||||
return copyInfohashFN(2);
|
break;
|
||||||
case "copyMagnetLink":
|
case "copyInfohash2":
|
||||||
return copyMagnetLinkFN();
|
setupClickEvent(() => copyInfohashFN(2));
|
||||||
case "copyID":
|
break;
|
||||||
return copyIdFN();
|
case "copyMagnetLink":
|
||||||
case "copyComment":
|
setupClickEvent(copyMagnetLinkFN);
|
||||||
return copyCommentFN();
|
break;
|
||||||
default:
|
case "copyID":
|
||||||
return "";
|
setupClickEvent(copyIdFN);
|
||||||
}
|
break;
|
||||||
|
case "copyComment":
|
||||||
|
setupClickEvent(copyCommentFN);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
addEventListener("visibilitychange", (event) => {
|
addEventListener("visibilitychange", (event) => {
|
||||||
if (document.hidden)
|
if (document.hidden)
|
||||||
|
|
63
src/webui/www/private/scripts/lib/clipboard-copy.js
Normal file
63
src/webui/www/private/scripts/lib/clipboard-copy.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*! clipboard-copy. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||||
|
/* 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 <span>
|
||||||
|
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 <span> 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -183,10 +183,9 @@ window.qBittorrent.PropPeers ??= (() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new ClipboardJS("#CopyPeerInfo", {
|
document.getElementById("CopyPeerInfo").addEventListener("click", async (event) => {
|
||||||
text: (trigger) => {
|
const text = torrentPeersTable.selectedRowsIds().join("\n");
|
||||||
return torrentPeersTable.selectedRowsIds().join("\n");
|
await clipboardCopy(text);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
torrentPeersTable.setup("torrentPeersTableDiv", "torrentPeersTableFixedHeaderDiv", torrentPeersContextMenu, true);
|
torrentPeersTable.setup("torrentPeersTableDiv", "torrentPeersTableFixedHeaderDiv", torrentPeersContextMenu, true);
|
||||||
|
|
|
@ -248,10 +248,9 @@ window.qBittorrent.PropTrackers ??= (() => {
|
||||||
torrentTrackersTable.clear();
|
torrentTrackersTable.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
new ClipboardJS("#CopyTrackerUrl", {
|
document.getElementById("CopyTrackerUrl").addEventListener("click", async (event) => {
|
||||||
text: (trigger) => {
|
const text = torrentTrackersTable.selectedRowsIds().join("\n");
|
||||||
return torrentTrackersTable.selectedRowsIds().join("\n");
|
await clipboardCopy(text);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
torrentTrackersTable.setup("torrentTrackersTableDiv", "torrentTrackersTableFixedHeaderDiv", torrentTrackersContextMenu, true);
|
torrentTrackersTable.setup("torrentTrackersTableDiv", "torrentTrackersTableFixedHeaderDiv", torrentTrackersContextMenu, true);
|
||||||
|
|
|
@ -219,10 +219,9 @@ window.qBittorrent.PropWebseeds ??= (() => {
|
||||||
torrentWebseedsTable.clear();
|
torrentWebseedsTable.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
new ClipboardJS("#CopyWebseedUrl", {
|
document.getElementById("CopyWebseedUrl").addEventListener("click", async (event) => {
|
||||||
text: (trigger) => {
|
const text = torrentWebseedsTable.selectedRowsIds().join("\n");
|
||||||
return torrentWebseedsTable.selectedRowsIds().join("\n");
|
await clipboardCopy(text);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
torrentWebseedsTable.setup("torrentWebseedsTableDiv", "torrentWebseedsTableFixedHeaderDiv", torrentWebseedsContextMenu, true);
|
torrentWebseedsTable.setup("torrentWebseedsTableDiv", "torrentWebseedsTableFixedHeaderDiv", torrentWebseedsContextMenu, true);
|
||||||
|
|
|
@ -866,20 +866,20 @@ window.qBittorrent.Search ??= (() => {
|
||||||
state.loadResultsTimer = loadSearchResultsData.delay(500, this, searchId);
|
state.loadResultsTimer = loadSearchResultsData.delay(500, this, searchId);
|
||||||
};
|
};
|
||||||
|
|
||||||
new ClipboardJS(".copySearchDataToClipboard", {
|
for (const element of document.getElementsByClassName("copySearchDataToClipboard")) {
|
||||||
text: (trigger) => {
|
const setupClickEvent = (textFunc) => element.addEventListener("click", async (event) => await clipboardCopy(textFunc()));
|
||||||
switch (trigger.id) {
|
switch (element.id) {
|
||||||
case "copySearchTorrentName":
|
case "copySearchTorrentName":
|
||||||
return copySearchTorrentName();
|
setupClickEvent(copySearchTorrentName);
|
||||||
case "copySearchTorrentDownloadLink":
|
break;
|
||||||
return copySearchTorrentDownloadLink();
|
case "copySearchTorrentDownloadLink":
|
||||||
case "copySearchTorrentDescriptionUrl":
|
setupClickEvent(copySearchTorrentDownloadLink);
|
||||||
return copySearchTorrentDescriptionUrl();
|
break;
|
||||||
default:
|
case "copySearchTorrentDescriptionUrl":
|
||||||
return "";
|
setupClickEvent(copySearchTorrentDescriptionUrl);
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return exports();
|
return exports();
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -144,7 +144,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul id="logTableMenu" class="contextMenu">
|
<ul id="logTableMenu" class="contextMenu">
|
||||||
<li><a href="#" class="copyLogDataToClipboard"><img src="images/edit-copy.svg" alt="QBT_TR(Copy)QBT_TR[CONTEXT=ExecutionLogWidget]">QBT_TR(Copy)QBT_TR[CONTEXT=ExecutionLogWidget]</a></li>
|
<li><a href="#" id="copyLogDataToClipboard"><img src="images/edit-copy.svg" alt="QBT_TR(Copy)QBT_TR[CONTEXT=ExecutionLogWidget]">QBT_TR(Copy)QBT_TR[CONTEXT=ExecutionLogWidget]</a></li>
|
||||||
<li><a href="#Clear"><img src="images/list-remove.svg" alt="QBT_TR(Clear)QBT_TR[CONTEXT=ExecutionLogWidget]">QBT_TR(Clear)QBT_TR[CONTEXT=ExecutionLogWidget]</a></li>
|
<li><a href="#Clear"><img src="images/list-remove.svg" alt="QBT_TR(Clear)QBT_TR[CONTEXT=ExecutionLogWidget]">QBT_TR(Clear)QBT_TR[CONTEXT=ExecutionLogWidget]</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -418,15 +418,11 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
new ClipboardJS(".copyLogDataToClipboard", {
|
document.getElementById("copyLogDataToClipboard").addEventListener("click", async (event) => {
|
||||||
text: () => {
|
const instance = tableInfo[currentSelectedTab].instance;
|
||||||
const msg = [];
|
const type = (currentSelectedTab === "main") ? "message" : "ip";
|
||||||
tableInfo[currentSelectedTab].instance.selectedRowsIds().forEach((rowId) => {
|
const msg = instance.selectedRowsIds().map((rowId) => instance.getRow(rowId).full_data[type]);
|
||||||
msg.push(tableInfo[currentSelectedTab].instance.getRow(rowId).full_data[(currentSelectedTab === "main") ? "message" : "ip"]);
|
await clipboardCopy(msg.join("\n"));
|
||||||
});
|
|
||||||
|
|
||||||
return msg.join("\n");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return exports();
|
return exports();
|
||||||
|
|
|
@ -277,17 +277,16 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new ClipboardJS("#CopyFeedURL", {
|
document.getElementById("CopyFeedURL").addEventListener("click", async (event) => {
|
||||||
text: () => {
|
let joined = "";
|
||||||
let joined = "";
|
for (const rowID of rssFeedTable.selectedRows) {
|
||||||
for (const rowID of rssFeedTable.selectedRows) {
|
const row = rssFeedTable.getRow(rowID);
|
||||||
const row = rssFeedTable.getRow(rowID);
|
if (row.full_data.dataUid !== "")
|
||||||
if (row.full_data.dataUid !== "")
|
joined += `${row.full_data.dataUrl}\n`;
|
||||||
joined += `${row.full_data.dataUrl}\n`;
|
|
||||||
}
|
|
||||||
return joined.slice(0, -1);
|
|
||||||
}
|
}
|
||||||
|
await clipboardCopy(joined.slice(0, -1));
|
||||||
});
|
});
|
||||||
|
|
||||||
rssFeedTable.setup("rssFeedTableDiv", "rssFeedFixedHeaderDiv", rssFeedContextMenu);
|
rssFeedTable.setup("rssFeedTableDiv", "rssFeedFixedHeaderDiv", rssFeedContextMenu);
|
||||||
|
|
||||||
const rssArticleContextMenu = new window.qBittorrent.ContextMenu.RssArticleContextMenu({
|
const rssArticleContextMenu = new window.qBittorrent.ContextMenu.RssArticleContextMenu({
|
||||||
|
|
|
@ -400,7 +400,7 @@
|
||||||
<file>private/scripts/dynamicTable.js</file>
|
<file>private/scripts/dynamicTable.js</file>
|
||||||
<file>private/scripts/file-tree.js</file>
|
<file>private/scripts/file-tree.js</file>
|
||||||
<file>private/scripts/filesystem.js</file>
|
<file>private/scripts/filesystem.js</file>
|
||||||
<file>private/scripts/lib/clipboard.min.js</file>
|
<file>private/scripts/lib/clipboard-copy.js</file>
|
||||||
<file>private/scripts/lib/mocha.min.js</file>
|
<file>private/scripts/lib/mocha.min.js</file>
|
||||||
<file>private/scripts/lib/MooTools-Core-1.6.0-compat-compressed.js</file>
|
<file>private/scripts/lib/MooTools-Core-1.6.0-compat-compressed.js</file>
|
||||||
<file>private/scripts/lib/MooTools-More-1.6.0-compat-compressed.js</file>
|
<file>private/scripts/lib/MooTools-More-1.6.0-compat-compressed.js</file>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue