From ccfbef066b5f705c23fde8a5c63698b2520a8329 Mon Sep 17 00:00:00 2001 From: bb2 <23148629+bb2@users.noreply.github.com> Date: Sat, 23 May 2026 19:57:49 +0800 Subject: [PATCH 1/3] UI: Decode URL in text field for better readability **Optimize visual display:** Decodes the URL displayed in the input field using `decodeURIComponent`. This makes the displayed link more user-friendly and intuitive, avoiding a screen full of percent signs in internationalized scenarios where collection folder names contain non-English characters or special symbols. **Ensure copy safety:** Preserves the original, encoded standard URL internally as `_completedUrl`. Clicking the "Copy" button or manually selecting the entire text box to copy will still place the original, encoded standard link into the clipboard. --- .../web/internal_data/js/utils/url_text.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/radicale/web/internal_data/js/utils/url_text.js b/radicale/web/internal_data/js/utils/url_text.js index 004bdbbe..c05d22fa 100644 --- a/radicale/web/internal_data/js/utils/url_text.js +++ b/radicale/web/internal_data/js/utils/url_text.js @@ -38,6 +38,19 @@ export class UrlTextHandler { this._copyButton = copyButton; this._userIndex = -1; + // Only encode the URL if the entire text is selected. + this._element.addEventListener("copy", (event) => { + const selectedText = window.getSelection().toString(); + const totalText = this._element.value; + + // Check if the selected text length matches the total text length. + if (selectedText && selectedText.length === totalText.length) { + event.preventDefault(); + event.clipboardData.setData("text/plain", this._completedUrl); + } + // Allow default copying if only a part of the text is selected. + }); + this._element.addEventListener("focusin", () => { this._element.setSelectionRange(0, 99999); this._updateScroll(); @@ -88,7 +101,7 @@ export class UrlTextHandler { _oncopy() { if (!this._element.value) return; - navigator.clipboard.writeText(this._element.value).then(() => { + navigator.clipboard.writeText(this._completedUrl).then(() => { if (this._copyButton) { this._copyButton.classList.add("copied"); this._copyButton.title = "Copied!"; @@ -108,7 +121,8 @@ export class UrlTextHandler { * @param {string} href The href to set. */ setHref(href) { - this._element.value = completeHref(href); + this._completedUrl = completeHref(href); + this._element.value = decodeURIComponent(this._completedUrl); this._update_username_index(); this._updateScroll(); From d16501f1f34ff85910a6378656c1f276118480a1 Mon Sep 17 00:00:00 2001 From: bb2 <23148629+bb2@users.noreply.github.com> Date: Sat, 23 May 2026 21:16:23 +0800 Subject: [PATCH 2/3] Fix JS Type Check error --- .../web/internal_data/js/utils/url_text.js | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/radicale/web/internal_data/js/utils/url_text.js b/radicale/web/internal_data/js/utils/url_text.js index c05d22fa..20b38246 100644 --- a/radicale/web/internal_data/js/utils/url_text.js +++ b/radicale/web/internal_data/js/utils/url_text.js @@ -37,19 +37,22 @@ export class UrlTextHandler { this._element = element; this._copyButton = copyButton; this._userIndex = -1; + this._completedUrl = ""; // Only encode the URL if the entire text is selected. - this._element.addEventListener("copy", (event) => { - const selectedText = window.getSelection().toString(); - const totalText = this._element.value; + if (this._element) { + this._element.addEventListener("copy", (event) => { + const selectedText = window.getSelection().toString(); + const totalText = this._element.value; - // Check if the selected text length matches the total text length. - if (selectedText && selectedText.length === totalText.length) { - event.preventDefault(); - event.clipboardData.setData("text/plain", this._completedUrl); - } - // Allow default copying if only a part of the text is selected. - }); + // Check if the selected text length matches the total text length. + if (event.clipboardData && selectedText && selectedText.length === totalText.length) { + event.preventDefault(); + event.clipboardData.setData("text/plain", this._completedUrl || ""); + } + // Allow default copying if only a part of the text is selected. + }); + } this._element.addEventListener("focusin", () => { this._element.setSelectionRange(0, 99999); @@ -101,7 +104,7 @@ export class UrlTextHandler { _oncopy() { if (!this._element.value) return; - navigator.clipboard.writeText(this._completedUrl).then(() => { + navigator.clipboard.writeText(this._completedUrl || "").then(() => { if (this._copyButton) { this._copyButton.classList.add("copied"); this._copyButton.title = "Copied!"; From 877fb3c50c4ae15c38f05a4a5962dfcdacdbc999 Mon Sep 17 00:00:00 2001 From: bb2 <23148629+bb2@users.noreply.github.com> Date: Sat, 23 May 2026 21:26:45 +0800 Subject: [PATCH 3/3] Fix JS Type Check error (v2) --- radicale/web/internal_data/js/utils/url_text.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/web/internal_data/js/utils/url_text.js b/radicale/web/internal_data/js/utils/url_text.js index 20b38246..67bae393 100644 --- a/radicale/web/internal_data/js/utils/url_text.js +++ b/radicale/web/internal_data/js/utils/url_text.js @@ -42,7 +42,7 @@ export class UrlTextHandler { // Only encode the URL if the entire text is selected. if (this._element) { this._element.addEventListener("copy", (event) => { - const selectedText = window.getSelection().toString(); + const selectedText = window.getSelection()?.toString(); const totalText = this._element.value; // Check if the selected text length matches the total text length.