From 3075888d26d9fbbd56a2615ae51fe8d122ad62b2 Mon Sep 17 00:00:00 2001
From: Constantin Piber <59023762+cpiber@users.noreply.github.com>
Date: Tue, 19 Aug 2025 22:01:31 +0300
Subject: [PATCH] [#1575] Support copy & paste (#1593)
* [#1575] Support paste
* WebView: Implement copy
* Localize copy dialog, lint
* Implement a custom context menu for copy/paste
* Remove click event which causes double events
* WebView: Fix input events broken by moved preventDefault
We want to fall back to the `input` event for Android bug and paste, but
we want to prevent the event for the others, so change the order
---
.../moko-resources/values/base/strings.xml | 3 +
server/src/main/jte/Webview.kte | 192 ++++++++++++++++--
.../tachidesk/global/impl/KcefWebView.kt | 54 ++++-
.../suwayomi/tachidesk/global/impl/WebView.kt | 16 ++
4 files changed, 249 insertions(+), 16 deletions(-)
diff --git a/server/i18n/src/commonMain/moko-resources/values/base/strings.xml b/server/i18n/src/commonMain/moko-resources/values/base/strings.xml
index b55c3da5..812cbd9f 100644
--- a/server/i18n/src/commonMain/moko-resources/values/base/strings.xml
+++ b/server/i18n/src/commonMain/moko-resources/values/base/strings.xml
@@ -130,6 +130,7 @@
Error
Version %1$s
+ Close
Suwayomi WebView
Disconnected, please refresh
@@ -138,6 +139,8 @@
Initializing... Please wait
Enter a URL to get started
Loading page...
+ Copy to Clipboard
+ Automatic clipboard copy failed, please use the input below to manually copy the value.
Enter URL...
Suwayomi Login
diff --git a/server/src/main/jte/Webview.kte b/server/src/main/jte/Webview.kte
index 6dfc049a..f4b541c8 100644
--- a/server/src/main/jte/Webview.kte
+++ b/server/src/main/jte/Webview.kte
@@ -131,6 +131,87 @@
main .status:empty {
display: none;
}
+ main .contextmenu {
+ display: none;
+ position: absolute;
+ right: 0;
+ max-width: fit-content;
+ min-height: calc(1.5em + 2px + 2px + 4px);
+ min-width: 120px;
+ flex-wrap: wrap;
+ border-radius: 4px;
+ border: 1px solid #333;
+ }
+ main .contextmenu.show {
+ display: flex;
+ }
+ main .contextmenu button {
+ all: unset;
+ line-height: 1.5;
+ flex-grow: 1;
+ background: white;
+ transition: background 0.1s ease-in-out;
+ cursor: pointer;
+ border: 0.5px solid #666;
+ padding: 2px 4px;
+ text-align: center;
+ }
+ main .contextmenu button:hover {
+ background: #eee;
+ }
+ .copydialog {
+ display: none;
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ padding: 6px;
+ }
+ .copydialog.show {
+ display: block;
+ }
+ .copydialog::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: black;
+ opacity: 0.3;
+ }
+ .copydialog__inner {
+ position: relative;
+ max-width: 960px;
+ border-radius: 8px;
+ border: 1px solid #333;
+ background: #eee;
+ padding: 8px;
+ margin: auto;
+ height: 100%;
+ }
+ .copydialog__title {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ }
+ .copydialog input {
+ width: 100%;
+ }
+ .copydialog .close {
+ flex-shrink: 1;
+ all: unset;
+ cursor: pointer;
+ align-self: start;
+ font-size: 2rem;
+ line-height: 1;
+ }
+ @media (min-width: 500px) {
+ .copydialog {
+ padding: 24px;
+ }
+ .copydialog__inner {
+ padding: 12px 18px;
+ height: auto;
+ }
+ }
/* https://css-tricks.com/snippets/css/css-triangle/ */
.arrow-right {
@@ -160,10 +241,30 @@
+
+
+
+
+
${MR.strings.webview_label_copy.localized(locale)}
+
+
+
${MR.strings.webview_label_copy_description.localized(locale)}
+
+
+