summaryrefslogtreecommitdiffstats
path: root/g4f
diff options
context:
space:
mode:
Diffstat (limited to 'g4f')
-rw-r--r--g4f/gui/client/static/js/chat.v1.js34
-rw-r--r--g4f/gui/client/static/js/highlightjs-copy.min.js55
-rw-r--r--g4f/version.py2
3 files changed, 88 insertions, 3 deletions
diff --git a/g4f/gui/client/static/js/chat.v1.js b/g4f/gui/client/static/js/chat.v1.js
index 10b5c1f0..9bf07046 100644
--- a/g4f/gui/client/static/js/chat.v1.js
+++ b/g4f/gui/client/static/js/chat.v1.js
@@ -57,6 +57,25 @@ function filter_message(text) {
)
}
+function fallback_clipboard (text) {
+ var textBox = document.createElement("textarea");
+ textBox.value = text;
+ textBox.style.top = "0";
+ textBox.style.left = "0";
+ textBox.style.position = "fixed";
+ document.body.appendChild(textBox);
+ textBox.focus();
+ textBox.select();
+ try {
+ var success = document.execCommand('copy');
+ var msg = success ? 'succeeded' : 'failed';
+ console.log('Clipboard Fallback: Copying text command ' + msg);
+ } catch (e) {
+ console.error('Clipboard Fallback: Unable to copy', e);
+ }
+ document.body.removeChild(textBox);
+}
+
hljs.addPlugin(new CopyButtonPlugin());
let typesetPromise = Promise.resolve();
const highlight = (container) => {
@@ -88,18 +107,31 @@ const register_message_buttons = async () => {
})
}
});
+
document.querySelectorAll(".message .fa-clipboard").forEach(async (el) => {
if (!("click" in el.dataset)) {
el.dataset.click = "true";
el.addEventListener("click", async () => {
const message_el = el.parentElement.parentElement.parentElement;
const copyText = await get_message(window.conversation_id, message_el.dataset.index);
- navigator.clipboard.writeText(copyText);
+
+ try {
+ if (!navigator.clipboard) {
+ throw new Error("navigator.clipboard: Clipboard API unavailable.");
+ }
+ await navigator.clipboard.writeText(copyText);
+ } catch (e) {
+ console.error(e);
+ console.error("Clipboard API writeText() failed! Fallback to document.exec(\"copy\")...");
+ fallback_clipboard(copyText);
+ }
+
el.classList.add("clicked");
setTimeout(() => el.classList.remove("clicked"), 1000);
})
}
});
+
document.querySelectorAll(".message .fa-volume-high").forEach(async (el) => {
if (!("click" in el.dataset)) {
el.dataset.click = "true";
diff --git a/g4f/gui/client/static/js/highlightjs-copy.min.js b/g4f/gui/client/static/js/highlightjs-copy.min.js
index ac11d33e..cd8ae957 100644
--- a/g4f/gui/client/static/js/highlightjs-copy.min.js
+++ b/g4f/gui/client/static/js/highlightjs-copy.min.js
@@ -1 +1,54 @@
-class CopyButtonPlugin{constructor(options={}){self.hook=options.hook;self.callback=options.callback}"after:highlightElement"({el,text}){let button=Object.assign(document.createElement("button"),{innerHTML:"Copy",className:"hljs-copy-button"});button.dataset.copied=false;el.parentElement.classList.add("hljs-copy-wrapper");el.parentElement.appendChild(button);el.parentElement.style.setProperty("--hljs-theme-background",window.getComputedStyle(el).backgroundColor);button.onclick=function(){if(!navigator.clipboard)return;let newText=text;if(hook&&typeof hook==="function"){newText=hook(text,el)||text}navigator.clipboard.writeText(newText).then(function(){button.innerHTML="Copied!";button.dataset.copied=true;let alert=Object.assign(document.createElement("div"),{role:"status",className:"hljs-copy-alert",innerHTML:"Copied to clipboard"});el.parentElement.appendChild(alert);setTimeout(()=>{button.innerHTML="Copy";button.dataset.copied=false;el.parentElement.removeChild(alert);alert=null},2e3)}).then(function(){if(typeof callback==="function")return callback(newText,el)})}}} \ No newline at end of file
+class CopyButtonPlugin {
+ constructor(options = {}) {
+ self.hook = options.hook;
+ self.callback = options.callback
+ }
+ "after:highlightElement"({
+ el,
+ text
+ }) {
+ let button = Object.assign(document.createElement("button"), {
+ innerHTML: "Copy",
+ className: "hljs-copy-button"
+ });
+ button.dataset.copied = false;
+ el.parentElement.classList.add("hljs-copy-wrapper");
+ el.parentElement.appendChild(button);
+ el.parentElement.style.setProperty("--hljs-theme-background", window.getComputedStyle(el).backgroundColor);
+ button.onclick = async () => {
+ let newText = text;
+ if (hook && typeof hook === "function") {
+ newText = hook(text, el) || text
+ }
+ try {
+ if (!navigator.clipboard) {
+ throw new Error("navigator.clipboard: Clipboard API unavailable.");
+ }
+ await navigator.clipboard.writeText(newText);
+ } catch (e) {
+ console.error(e);
+ console.error("Clipboard API writeText() failed! Fallback to document.exec(\"copy\")...");
+ fallback_clipboard(newText);
+ }
+ button.innerHTML = "Copied!";
+ button.dataset.copied = true;
+ let alert = Object.assign(document.createElement("div"), {
+ role: "status",
+ className: "hljs-copy-alert",
+ innerHTML: "Copied to clipboard"
+ });
+ el.parentElement.appendChild(alert);
+ setTimeout(() => {
+ button.innerHTML = "Copy";
+ button.dataset.copied = false;
+ el.parentElement.removeChild(alert);
+ alert = null
+ }, 2e3)
+ }
+
+
+ if (typeof callback === "function") return callback(newText, el);
+
+ }
+
+}
diff --git a/g4f/version.py b/g4f/version.py
index eda2b8fe..403ce370 100644
--- a/g4f/version.py
+++ b/g4f/version.py
@@ -116,4 +116,4 @@ class VersionUtils:
except Exception as e:
print(f'Failed to check g4f version: {e}')
-utils = VersionUtils() \ No newline at end of file
+utils = VersionUtils()