From 055223bfdf6ab3955655c09407069df2726a1349 Mon Sep 17 00:00:00 2001
From: klarkxy <278370456@qq.com>
Date: Fri, 13 Mar 2026 19:32:38 +0800
Subject: [PATCH] feat(problem): add copy button to markdown code blocks
Add a copy button to markdown code blocks in the problem view for easier code snippet copying. The button appears in the top-right corner of code blocks and provides visual feedback on copy success or failure. This improves user experience by eliminating the need to manually select and copy code.
---
web/template/syzoj/problem.php | 75 ++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/web/template/syzoj/problem.php b/web/template/syzoj/problem.php
index 335f4a3..606aebe 100644
--- a/web/template/syzoj/problem.php
+++ b/web/template/syzoj/problem.php
@@ -33,6 +33,29 @@ if ($pr_flag) {
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.05);
}
+
+ .md pre {
+ position: relative;
+ }
+
+ .md-code-copy {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ z-index: 1;
+ font-size: 12px;
+ color: #4d4d4d;
+ background-color: #fff;
+ border: 1px solid #e0e0e0;
+ padding: 2px 8px;
+ border-radius: 4px;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+ }
+
+ .md-code-copy:hover {
+ background-color: #f5f5f5;
+ }
@@ -501,6 +524,56 @@ if ($pr_flag) {
$(document).ready(function () {
$("#creator").load("problem-ajax.php?pid=");
+
+ function copyText(content, onSuccess, onFail) {
+ if (navigator.clipboard && window.isSecureContext) {
+ navigator.clipboard.writeText(content).then(onSuccess).catch(onFail);
+ return;
+ }
+ const textarea = document.createElement('textarea');
+ textarea.value = content;
+ textarea.style.position = 'fixed';
+ textarea.style.left = '-9999px';
+ document.body.appendChild(textarea);
+ textarea.focus();
+ textarea.select();
+ try {
+ const copied = document.execCommand('copy');
+ copied ? onSuccess() : onFail();
+ } catch (err) {
+ onFail();
+ }
+ document.body.removeChild(textarea);
+ }
+
+ function initMarkdownCodeCopy() {
+ $('.md pre').each(function () {
+ const pre = $(this);
+ if (pre.find('.md-code-copy').length > 0) return;
+
+ const btn = $('');
+ btn.on('click', function () {
+ const code = pre.find('code').first();
+ const text = code.length > 0 ? code.text() : pre.text();
+ const currentBtn = $(this);
+
+ copyText(
+ text,
+ function () {
+ currentBtn.text('!');
+ setTimeout(function () { currentBtn.text(''); }, 1500);
+ },
+ function () {
+ currentBtn.text('!');
+ setTimeout(function () { currentBtn.text(''); }, 1500);
+ }
+ );
+ });
+
+ pre.prepend(btn);
+ });
+ }
+
marked.use({
// 开启异步渲染
@@ -557,6 +630,8 @@ if ($pr_flag) {
"text-align": "center"
});
+ initMarkdownCodeCopy();
+
//单纯文本1. A. B. C. D. 自动变控件
$('span[class=auto_select]').each(function () {