Spaces:
Sleeping
Sleeping
feat: 增加代码块复制功能, resolve #241 (#324)
Browse files* feat: 增加js支持
* fix: 修正缩进,增加本地js读取
Co-authored-by: Chen Zirui <1617335718@qq.com>
Co-authored-by: Tuchuanhuhuhu <gzblog@hdu.edu.cn>
Co-authored-by: mzlegion <mzhao.ouo@gmail.com>
* feat: 增加代码块复制功能
---------
Co-authored-by: Chen Zirui <1617335718@qq.com>
Co-authored-by: Tuchuanhuhuhu <gzblog@hdu.edu.cn>
Co-authored-by: mzlegion <mzhao.ouo@gmail.com>
- ChuanhuChatbot.py +1 -0
- assets/Kelpy-Codos.js +76 -0
- assets/custom.js +1 -0
- overwrites.py +17 -0
ChuanhuChatbot.py
CHANGED
@@ -434,6 +434,7 @@ logging.info(
|
|
434 |
demo.title = "川虎ChatGPT 🚀"
|
435 |
|
436 |
if __name__ == "__main__":
|
|
|
437 |
# if running in Docker
|
438 |
if dockerflag:
|
439 |
if authflag:
|
|
|
434 |
demo.title = "川虎ChatGPT 🚀"
|
435 |
|
436 |
if __name__ == "__main__":
|
437 |
+
reload_javascript()
|
438 |
# if running in Docker
|
439 |
if dockerflag:
|
440 |
if authflag:
|
assets/Kelpy-Codos.js
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 ChatGPT especially.
|
7 |
+
// Based on Chuanhu ChatGPT version: ac04408 (2023-3-22)
|
8 |
+
// @license GPL-3.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.js
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
// custom javascript here
|
overwrites.py
CHANGED
@@ -36,3 +36,20 @@ def postprocess(
|
|
36 |
else:
|
37 |
y[-1] = (convert_user(y[-1][0]), convert_mdtext(y[-1][1]))
|
38 |
return y
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
else:
|
37 |
y[-1] = (convert_user(y[-1][0]), convert_mdtext(y[-1][1]))
|
38 |
return y
|
39 |
+
|
40 |
+
with open("./assets/custom.js", "r", encoding="utf-8") as f, open("./assets/Kelpy-Codos.js", "r", encoding="utf-8") as f2:
|
41 |
+
customJS = f.read()
|
42 |
+
kelpyCodos = f2.read()
|
43 |
+
|
44 |
+
def reload_javascript():
|
45 |
+
print("Reloading javascript...")
|
46 |
+
js = f'<script>{customJS}</script><script>{kelpyCodos}</script>'
|
47 |
+
def template_response(*args, **kwargs):
|
48 |
+
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
49 |
+
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
|
50 |
+
res.init_headers()
|
51 |
+
return res
|
52 |
+
|
53 |
+
gr.routes.templates.TemplateResponse = template_response
|
54 |
+
|
55 |
+
GradioTemplateResponseOriginal = gr.routes.templates.TemplateResponse
|