ui: add clipboard fallback for copy button (#34092)#34171
ui: add clipboard fallback for copy button (#34092)#34171lsdcc01 wants to merge 2 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR fixes a bug where the "Copy as markdown" button silently failed in HTTP (non-HTTPS) contexts — such as Key changes:
Confidence Score: 4/5
Last reviewed commit: ddae218 |
| try { | ||
| const textarea = document.createElement("textarea"); | ||
| textarea.value = text; | ||
| textarea.style.position = "fixed"; | ||
| textarea.style.opacity = "0"; | ||
| document.body.appendChild(textarea); | ||
| textarea.select(); | ||
| success = document.execCommand("copy"); | ||
| document.body.removeChild(textarea); | ||
| } catch (err) { | ||
| console.error("Failed to copy:", err); | ||
| } |
There was a problem hiding this comment.
Textarea not cleaned up if execCommand throws
If textarea.select() or document.execCommand("copy") throws before reaching document.body.removeChild(textarea), the hidden textarea is permanently left in the DOM. While this matches the existing pattern in src/auto-reply/reply/export-html/template.js, using a finally block guarantees cleanup regardless of outcome:
try {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.opacity = "0";
document.body.appendChild(textarea);
try {
textarea.select();
success = document.execCommand("copy");
} finally {
document.body.removeChild(textarea);
}
} catch (err) {
console.error("Failed to copy:", err);
}
This ensures the element is always removed even when an unexpected exception is raised.
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/chat/copy-as-markdown.ts
Line: 32-43
Comment:
**Textarea not cleaned up if `execCommand` throws**
If `textarea.select()` or `document.execCommand("copy")` throws before reaching `document.body.removeChild(textarea)`, the hidden textarea is permanently left in the DOM. While this matches the existing pattern in `src/auto-reply/reply/export-html/template.js`, using a `finally` block guarantees cleanup regardless of outcome:
```
try {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.opacity = "0";
document.body.appendChild(textarea);
try {
textarea.select();
success = document.execCommand("copy");
} finally {
document.body.removeChild(textarea);
}
} catch (err) {
console.error("Failed to copy:", err);
}
```
This ensures the element is always removed even when an unexpected exception is raised.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ddae218e1c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
ui/src/ui/chat/copy-as-markdown.ts
Outdated
| success = document.execCommand("copy"); | ||
| document.body.removeChild(textarea); |
There was a problem hiding this comment.
Always clean up fallback textarea on copy failure
If document.execCommand("copy") (or textarea.select()) throws in the fallback path—for example on browsers where execCommand is unavailable or blocked—the temporary <textarea> is never removed because cleanup happens only after the successful call. In repeated failed copy attempts this leaks hidden nodes and leaves copied message text in the DOM longer than intended, so cleanup should be moved to a finally block.
Useful? React with 👍 / 👎.
PR #34092: Copy button clipboard fallback for HTTP context
Summary
http://192.168.x.x(non-HTTPS).navigator.clipboard.writeText()only works in secure contexts (HTTPS or localhost). Over HTTP it throws silently and the current code had no fallback.document.execCommand('copy')fallback via temporary textarea when Clipboard API fails, matching the pattern insrc/auto-reply/reply/export-html/template.js.Change Type
Scope
Linked Issue/PR
User-visible / Behavior Changes
Copy button now works when accessing the web UI over HTTP (e.g.
http://192.168.x.x). No change for HTTPS/localhost users.Security Impact
Repro + Verification
Environment
http://192.168.x.x(gateway web UI)Steps
Expected
Text is copied to clipboard.
Actual (before fix)
Nothing copied; button appears to do nothing.
Evidence
execCommand('copy').src/auto-reply/reply/export-html/template.jslines 1277–1291.Human Verification
pnpm checkpasses.Compatibility / Migration
Risks and Mitigations
execCommand('copy')is deprecated (but widely supported).