Spaces:
Sleeping
Sleeping
Keldos
commited on
Commit
•
44970ac
1
Parent(s):
e1ee750
fix & refactor: 解决拷贝代码框按钮消失的问题
Browse files但是,现在的代码可能有点问题……
mutationList中不存在新增bot message的addNode,只能用属性变化分析,可能会导致加button次数过多?
但是bot对话内容生成时又是不断覆盖pre的……因此不能用之前的抖动.5s,否则页面框会闪烁。
这可能会导致浏览器占用一些CPU和内存……希望有人能优化一下,谢谢
- assets/Kelpy-Codos.js +0 -76
- assets/custom.css +6 -1
- assets/custom.js +40 -0
- modules/overwrites.py +3 -5
assets/Kelpy-Codos.js
DELETED
@@ -1,76 +0,0 @@
|
|
1 |
-
// ==UserScript==
|
2 |
-
// @name Kelpy Codos
|
3 |
-
// @namespace https://github.com/Keldos-Li/Kelpy-Codos
|
4 |
-
// @version 1.0.5
|
5 |
-
// @author Keldos; https://keldos.me/
|
6 |
-
// @description Add copy button to PRE tags before CODE tag, for Chuanhu Chat especially.
|
7 |
-
// Based on Chuanhu Chat version: ac04408 (2023-3-22)
|
8 |
-
// @license Apache-2.0
|
9 |
-
// @grant none
|
10 |
-
// ==/UserScript==
|
11 |
-
|
12 |
-
(function () {
|
13 |
-
'use strict';
|
14 |
-
|
15 |
-
function addCopyButton(pre) {
|
16 |
-
var code = pre.querySelector('code');
|
17 |
-
if (!code) {
|
18 |
-
return; // 如果没有找到 <code> 元素,则不添加按钮
|
19 |
-
}
|
20 |
-
var firstChild = code.firstChild;
|
21 |
-
if (!firstChild) {
|
22 |
-
return; // 如果 <code> 元素没有子节点,则不添加按钮
|
23 |
-
}
|
24 |
-
var button = document.createElement('button');
|
25 |
-
button.textContent = '\uD83D\uDCCE'; // 使用 📎 符号作为“复制”按钮的文本
|
26 |
-
button.style.position = 'relative';
|
27 |
-
button.style.float = 'right';
|
28 |
-
button.style.fontSize = '1em'; // 可选:调整按钮大小
|
29 |
-
button.style.background = 'none'; // 可选:去掉背景颜色
|
30 |
-
button.style.border = 'none'; // 可选:去掉边框
|
31 |
-
button.style.cursor = 'pointer'; // 可选:显示指针样式
|
32 |
-
button.addEventListener('click', function () {
|
33 |
-
var range = document.createRange();
|
34 |
-
range.selectNodeContents(code);
|
35 |
-
range.setStartBefore(firstChild); // 将范围设置为第一个子节点之前
|
36 |
-
var selection = window.getSelection();
|
37 |
-
selection.removeAllRanges();
|
38 |
-
selection.addRange(range);
|
39 |
-
|
40 |
-
try {
|
41 |
-
var success = document.execCommand('copy');
|
42 |
-
if (success) {
|
43 |
-
button.textContent = '\u2714';
|
44 |
-
setTimeout(function () {
|
45 |
-
button.textContent = '\uD83D\uDCCE'; // 恢复按钮为“复制”
|
46 |
-
}, 2000);
|
47 |
-
} else {
|
48 |
-
button.textContent = '\u2716';
|
49 |
-
}
|
50 |
-
} catch (e) {
|
51 |
-
console.error(e);
|
52 |
-
button.textContent = '\u2716';
|
53 |
-
}
|
54 |
-
|
55 |
-
selection.removeAllRanges();
|
56 |
-
});
|
57 |
-
code.insertBefore(button, firstChild); // 将按钮插入到第一个子元素之前
|
58 |
-
}
|
59 |
-
|
60 |
-
function handleNewElements(mutationsList, observer) {
|
61 |
-
for (var mutation of mutationsList) {
|
62 |
-
if (mutation.type === 'childList') {
|
63 |
-
for (var node of mutation.addedNodes) {
|
64 |
-
if (node.nodeName === 'PRE') {
|
65 |
-
addCopyButton(node);
|
66 |
-
}
|
67 |
-
}
|
68 |
-
}
|
69 |
-
}
|
70 |
-
}
|
71 |
-
|
72 |
-
var observer = new MutationObserver(handleNewElements);
|
73 |
-
observer.observe(document.documentElement, { childList: true, subtree: true });
|
74 |
-
|
75 |
-
document.querySelectorAll('pre').forEach(addCopyButton);
|
76 |
-
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/custom.css
CHANGED
@@ -287,7 +287,12 @@ ol:not(.options), ul:not(.options) {
|
|
287 |
.toggle-md-btn {
|
288 |
top: 0;
|
289 |
}
|
290 |
-
|
|
|
|
|
|
|
|
|
|
|
291 |
|
292 |
.message-wrap>div img{
|
293 |
border-radius: 10px !important;
|
|
|
287 |
.toggle-md-btn {
|
288 |
top: 0;
|
289 |
}
|
290 |
+
.copy-code-btn {
|
291 |
+
position: relative;
|
292 |
+
float: right;
|
293 |
+
font-size: 1em;
|
294 |
+
cursor: pointer;
|
295 |
+
}
|
296 |
|
297 |
.message-wrap>div img{
|
298 |
border-radius: 10px !important;
|
assets/custom.js
CHANGED
@@ -333,6 +333,41 @@ function addChuanhuButton(botElement) {
|
|
333 |
botElement.insertBefore(toggleButton, copyButton);
|
334 |
}
|
335 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
336 |
function renderMarkdownText(message) {
|
337 |
var mdDiv = message.querySelector('.md-message');
|
338 |
if (mdDiv) mdDiv.classList.remove('hideM');
|
@@ -412,6 +447,8 @@ var mObserver = new MutationObserver(function (mutationsList) {
|
|
412 |
mathjaxUpdated = false;
|
413 |
}
|
414 |
saveHistoryHtml();
|
|
|
|
|
415 |
}
|
416 |
}
|
417 |
for (var node of mmutation.removedNodes) {
|
@@ -421,10 +458,13 @@ var mObserver = new MutationObserver(function (mutationsList) {
|
|
421 |
mathjaxUpdated = false;
|
422 |
}
|
423 |
saveHistoryHtml();
|
|
|
|
|
424 |
}
|
425 |
}
|
426 |
} else if (mmutation.type === 'attributes') {
|
427 |
if (mmutation.target.nodeType === 1 && mmutation.target.classList.contains('message') && mmutation.target.getAttribute('data-testid') === 'bot') {
|
|
|
428 |
if (isThrottled) break; // 为了防止重复不断疯狂渲染,加上等待_(:з」∠)_
|
429 |
isThrottled = true;
|
430 |
clearTimeout(timeoutId);
|
|
|
333 |
botElement.insertBefore(toggleButton, copyButton);
|
334 |
}
|
335 |
|
336 |
+
function addCopyCodeButton(pre) {
|
337 |
+
var code = null;
|
338 |
+
var firstChild = null;
|
339 |
+
code = pre.querySelector('code');
|
340 |
+
if (!code) return;
|
341 |
+
firstChild = code.querySelector('div');
|
342 |
+
if (!firstChild) return;
|
343 |
+
var oldCopyButton = null;
|
344 |
+
oldCopyButton = code.querySelector('button.copy-code-btn');
|
345 |
+
// if (oldCopyButton) oldCopyButton.remove();
|
346 |
+
if (oldCopyButton) return; // 没太有用,新生成的对话中始终会被pre覆盖,导致按钮消失,这段代码不启用……
|
347 |
+
var codeButton = document.createElement('button');
|
348 |
+
codeButton.classList.add('copy-code-btn');
|
349 |
+
codeButton.textContent = '\uD83D\uDCCE';
|
350 |
+
|
351 |
+
code.insertBefore(codeButton, firstChild);
|
352 |
+
codeButton.addEventListener('click', function () {
|
353 |
+
var range = document.createRange();
|
354 |
+
range.selectNodeContents(code);
|
355 |
+
range.setStartBefore(firstChild);
|
356 |
+
navigator.clipboard
|
357 |
+
.writeText(range.toString())
|
358 |
+
.then(() => {
|
359 |
+
codeButton.textContent = '\u2714';
|
360 |
+
setTimeout(function () {
|
361 |
+
codeButton.textContent = '\uD83D\uDCCE';
|
362 |
+
}, 2000);
|
363 |
+
})
|
364 |
+
.catch(e => {
|
365 |
+
console.error(e);
|
366 |
+
codeButton.textContent = '\u2716';
|
367 |
+
});
|
368 |
+
});
|
369 |
+
}
|
370 |
+
|
371 |
function renderMarkdownText(message) {
|
372 |
var mdDiv = message.querySelector('.md-message');
|
373 |
if (mdDiv) mdDiv.classList.remove('hideM');
|
|
|
447 |
mathjaxUpdated = false;
|
448 |
}
|
449 |
saveHistoryHtml();
|
450 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
|
451 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot pre').forEach(addCopyCodeButton);
|
452 |
}
|
453 |
}
|
454 |
for (var node of mmutation.removedNodes) {
|
|
|
458 |
mathjaxUpdated = false;
|
459 |
}
|
460 |
saveHistoryHtml();
|
461 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
|
462 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot pre').forEach(addCopyCodeButton);
|
463 |
}
|
464 |
}
|
465 |
} else if (mmutation.type === 'attributes') {
|
466 |
if (mmutation.target.nodeType === 1 && mmutation.target.classList.contains('message') && mmutation.target.getAttribute('data-testid') === 'bot') {
|
467 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot pre').forEach(addCopyCodeButton); // 目前写的是有点问题的,会导致加button次数过多,但是bot对话内容生成时又是不断覆盖pre的……
|
468 |
if (isThrottled) break; // 为了防止重复不断疯狂渲染,加上等待_(:з」∠)_
|
469 |
isThrottled = true;
|
470 |
clearTimeout(timeoutId);
|
modules/overwrites.py
CHANGED
@@ -77,16 +77,14 @@ def postprocess_chat_messages(
|
|
77 |
raise ValueError(f"Invalid message for Chatbot component: {chat_message}")
|
78 |
|
79 |
with open("./assets/custom.js", "r", encoding="utf-8") as f, \
|
80 |
-
open("./assets/
|
81 |
-
open("./assets/external-scripts.js", "r", encoding="utf-8") as f3:
|
82 |
customJS = f.read()
|
83 |
-
|
84 |
-
externalScripts = f3.read()
|
85 |
|
86 |
|
87 |
def reload_javascript():
|
88 |
print("Reloading javascript...")
|
89 |
-
js = f'<script>{customJS}</script><script
|
90 |
def template_response(*args, **kwargs):
|
91 |
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
92 |
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
|
|
|
77 |
raise ValueError(f"Invalid message for Chatbot component: {chat_message}")
|
78 |
|
79 |
with open("./assets/custom.js", "r", encoding="utf-8") as f, \
|
80 |
+
open("./assets/external-scripts.js", "r", encoding="utf-8") as f1:
|
|
|
81 |
customJS = f.read()
|
82 |
+
externalScripts = f1.read()
|
|
|
83 |
|
84 |
|
85 |
def reload_javascript():
|
86 |
print("Reloading javascript...")
|
87 |
+
js = f'<script>{customJS}</script><script async>{externalScripts}</script>'
|
88 |
def template_response(*args, **kwargs):
|
89 |
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
90 |
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
|