URL: https://dev.epicgames.com/community/assistant/fortnite/conversations/*
Issue:
When copying code from the Epic Games Assistant conversation pages, the copied text includes escaped HTML entities (e.g., <
, >
, &
) instead of the original characters like <
, >
, and &
.
Expected Behavior:
Copied code should retain its original formatting. For example:
verse
OnBegin<override>()<suspends> : void =
Actual Behavior:
Clipboard content after copying appears as:
verse
OnBegin<override>()<suspends> : void =
Impact:
This behavior breaks code formatting and causes confusion when pasting into external editors. Developers may unknowingly use malformed code due to improper character encoding.
Steps to Reproduce:
- Visit a conversation page like
https://dev.epicgames.com/community/assistant/fortnite/conversations/
- Copy a code snippet displayed by the assistant
- Paste it into a plain text editor (e.g., Notepad or VS Code)
- Observe that special characters are encoded
Suggestion:
Ensure copy handlers provide raw source text to clipboard without escaping characters unnecessarily. If innerHTML is used for retrieval, consider decoding or switching to textContent.
1 Like
I’ve temporarily fixed it on my end using this script so if anyone wants to use it, here’s the fix via VioletMonkey.
// ==UserScript==
// @name Epic Dev Clipboard Fix
// @match https://dev.epicgames.com/community/assistant/fortnite*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
// Decode HTML entities into their literal characters
const decodeEntities = str => {
const txt = document.createElement("textarea");
txt.innerHTML = str;
return txt.value;
};
// Your core interception logic in one init function
function initClipboardFix() {
// 1) Intercept DataTransfer.setData
const origSetData = DataTransfer.prototype.setData;
DataTransfer.prototype.setData = function(format, data) {
if (format === "text/plain") {
data = decodeEntities(data);
}
return origSetData.call(this, format, data);
};
// 2) Intercept navigator.clipboard.writeText
if (navigator.clipboard && navigator.clipboard.writeText) {
const origWrite = navigator.clipboard.writeText;
navigator.clipboard.writeText = function(text) {
return origWrite.call(this, decodeEntities(text));
};
}
// 3) Fallback copy-event handler (capture phase)
document.addEventListener("copy", e => {
let raw = e.clipboardData.getData("text/plain");
let clean = decodeEntities(raw);
e.clipboardData.setData("text/plain", clean);
e.preventDefault();
}, true);
}
// Run once on initial load
initClipboardFix();
// Re-run on SPA navigation (pushState, replaceState, popstate)
const wrapHistoryMethod = method => {
const orig = history[method];
history[method] = function(...args) {
const result = orig.apply(this, args);
initClipboardFix();
return result;
};
};
wrapHistoryMethod("pushState");
wrapHistoryMethod("replaceState");
window.addEventListener("popstate", initClipboardFix);
})();